TerminalManager.cpp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147
  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. // modified only, implicit
  533. StoredSessions->Save(false, false);
  534. }
  535. }
  536. }
  537. }
  538. //---------------------------------------------------------------------------
  539. void __fastcall TTerminalManager::CreateLogMemo()
  540. {
  541. assert(!FLogMemo);
  542. assert(ActiveTerminal);
  543. FLogMemo = new TLogMemo(Application);
  544. try
  545. {
  546. FLogMemo->SessionLog = ActiveTerminal->Log;
  547. FLogMemo->PopupMenu = NonVisualDataModule->LogMemoPopup;
  548. }
  549. catch (...)
  550. {
  551. delete FLogMemo;
  552. throw;
  553. }
  554. }
  555. //---------------------------------------------------------------------------
  556. void __fastcall TTerminalManager::FreeLogMemo()
  557. {
  558. assert(LogMemo);
  559. LogMemo->PopupMenu = NULL;
  560. SAFE_DESTROY(FLogMemo);
  561. }
  562. //---------------------------------------------------------------------------
  563. void __fastcall TTerminalManager::ApplicationException(TObject * /*Sender*/,
  564. Exception * E)
  565. {
  566. // can be null for example when exception is thrown on login dialog
  567. if (ActiveTerminal != NULL)
  568. {
  569. ActiveTerminal->ShowExtendedException(E);
  570. }
  571. else
  572. {
  573. ShowExtendedException(E);
  574. }
  575. }
  576. //---------------------------------------------------------------------------
  577. void __fastcall TTerminalManager::ApplicationShowHint(AnsiString & HintStr,
  578. bool & /*CanShow*/, THintInfo & HintInfo)
  579. {
  580. TLabel * HintLabel = dynamic_cast<TLabel *>(HintInfo.HintControl);
  581. if ((HintLabel != NULL) && (HintLabel->Caption == HintStr))
  582. {
  583. // Hack for transfer setting labels.
  584. // Should be converted to something like HintLabel()
  585. HintInfo.HintPos = HintLabel->ClientToScreen(TPoint(0, 0));
  586. HintInfo.HintMaxWidth = HintLabel->Width;
  587. HintInfo.HideTimeout = 100000; // "almost" never
  588. }
  589. else if (dynamic_cast<TProgressBar *>(HintInfo.HintControl) != NULL)
  590. {
  591. HintInfo.HideTimeout = 100000; // "almost" never
  592. HintInfo.ReshowTimeout = 500; // updated each 0.5s
  593. }
  594. else
  595. {
  596. HintInfo.HintMaxWidth = 300;
  597. }
  598. }
  599. //---------------------------------------------------------------------------
  600. void __fastcall TTerminalManager::ApplicationActivate(TObject * /*Sender*/)
  601. {
  602. // make sure the taskbar button of main window is pressed
  603. // (but only if main window is our application focused window,
  604. // note that there can also be an editor window)
  605. if ((ScpExplorer != NULL) && (Screen->ActiveForm == ScpExplorer))
  606. {
  607. SetActiveWindow(Application->Handle);
  608. }
  609. }
  610. //---------------------------------------------------------------------------
  611. void __fastcall TTerminalManager::DeleteLocalFile(const AnsiString FileName)
  612. {
  613. if (!RecursiveDeleteFile(FileName, WinConfiguration->DeleteToRecycleBin))
  614. {
  615. throw Exception(FMTLOAD(DELETE_LOCAL_FILE_ERROR, (FileName)));
  616. }
  617. }
  618. //---------------------------------------------------------------------------
  619. void __fastcall TTerminalManager::TerminalQueryUser(TObject * Sender,
  620. const AnsiString Query, TStrings * MoreMessages, int Answers,
  621. const TQueryParams * Params, int & Answer, TQueryType Type, void * /*Arg*/)
  622. {
  623. AnsiString HelpKeyword;
  624. TMessageParams MessageParams(Params);
  625. AnsiString AQuery = Query;
  626. if (Params != NULL)
  627. {
  628. HelpKeyword = Params->HelpKeyword;
  629. if (FLAGSET(Params->Params, qpFatalAbort))
  630. {
  631. AQuery = FMTLOAD(WARN_FATAL_ERROR, (AQuery));
  632. if (!MessageParams.TimerMessage.IsEmpty())
  633. {
  634. MessageParams.TimerMessage = FMTLOAD(WARN_FATAL_ERROR, (MessageParams.TimerMessage));
  635. }
  636. }
  637. }
  638. if (ScpExplorer)
  639. {
  640. Answer = ScpExplorer->MoreMessageDialog(AQuery, MoreMessages, Type, Answers,
  641. HelpKeyword, &MessageParams, dynamic_cast<TTerminal *>(Sender));
  642. }
  643. else
  644. {
  645. Answer = MoreMessageDialog(AQuery, MoreMessages, Type, Answers, HelpKeyword,
  646. &MessageParams);
  647. }
  648. }
  649. //---------------------------------------------------------------------------
  650. void __fastcall TTerminalManager::TerminalPromptUser(
  651. TTerminal * Terminal, AnsiString Prompt, TPromptKind Kind,
  652. AnsiString & Response, bool & Result, void * /*Arg*/)
  653. {
  654. if ((Kind == pkPrompt) && (FAuthenticateForm == NULL) &&
  655. (Terminal->Status != ssOpening))
  656. {
  657. AnsiString Caption = ::CutToChar(Prompt, '|', true);
  658. if (Prompt.IsEmpty())
  659. {
  660. Prompt = Caption;
  661. Caption = "";
  662. }
  663. Result = InputDialog(Caption, Prompt, Response);
  664. }
  665. else
  666. {
  667. TAuthenticateForm * AuthenticateForm = FAuthenticateForm;
  668. if (AuthenticateForm == NULL)
  669. {
  670. AuthenticateForm = new TAuthenticateForm(Application,
  671. Terminal->SessionData->SessionName);
  672. }
  673. try
  674. {
  675. Result = AuthenticateForm->PromptUser(Prompt, Kind, Response,
  676. (FAuthenticateForm != NULL));
  677. }
  678. __finally
  679. {
  680. if (FAuthenticateForm == NULL)
  681. {
  682. delete AuthenticateForm;
  683. }
  684. }
  685. }
  686. }
  687. //---------------------------------------------------------------------------
  688. void __fastcall TTerminalManager::TerminalDisplayBanner(
  689. TTerminal * /*Terminal*/, AnsiString SessionName,
  690. const AnsiString & Banner, bool & NeverShowAgain, int Options)
  691. {
  692. assert(FAuthenticateForm != NULL);
  693. TAuthenticateForm * AuthenticateForm = FAuthenticateForm;
  694. if (AuthenticateForm == NULL)
  695. {
  696. AuthenticateForm = new TAuthenticateForm(Application, SessionName);
  697. }
  698. try
  699. {
  700. AuthenticateForm->Banner(Banner, NeverShowAgain, Options);
  701. }
  702. __finally
  703. {
  704. if (FAuthenticateForm == NULL)
  705. {
  706. delete AuthenticateForm;
  707. }
  708. }
  709. }
  710. //---------------------------------------------------------------------------
  711. void __fastcall TTerminalManager::TerminalShowExtendedException(
  712. TTerminal * Terminal, Exception * E, void * /*Arg*/)
  713. {
  714. if (ScpExplorer)
  715. {
  716. ScpExplorer->ShowExtendedException(Terminal, E);
  717. }
  718. else
  719. {
  720. ShowExtendedExceptionEx(Terminal, E);
  721. }
  722. }
  723. //---------------------------------------------------------------------------
  724. void __fastcall TTerminalManager::TerminalReadDirectoryProgress(
  725. TObject * /*Sender*/, int Progress, bool & Cancel)
  726. {
  727. static TDateTime DirectoryReadingProgressDelay(0, 0, 1, 500);
  728. if (Progress == 0)
  729. {
  730. if (ScpExplorer != NULL)
  731. {
  732. ScpExplorer->LockWindow();
  733. }
  734. FDirectoryReadingStart = Now();
  735. if (!FProgressTitle.IsEmpty())
  736. {
  737. FProgressTitle = "";
  738. UpdateAppTitle();
  739. }
  740. // Reset "was ESC ever pressed?" state
  741. GetAsyncKeyState(VK_ESCAPE);
  742. }
  743. else if (Progress < 0)
  744. {
  745. if (Progress == -2)
  746. {
  747. // cancelled
  748. if (ScpExplorer != NULL)
  749. {
  750. ScpExplorer->ReadDirectoryCancelled();
  751. }
  752. }
  753. else
  754. {
  755. if (ScpExplorer != NULL)
  756. {
  757. ScpExplorer->UnlockWindow();
  758. }
  759. FProgressTitle = "";
  760. UpdateAppTitle();
  761. }
  762. }
  763. else
  764. {
  765. // If the least significant bit is set,
  766. // the key was pressed after the previous call to GetAsyncKeyState.
  767. int KeyState = GetAsyncKeyState(VK_ESCAPE);
  768. if (FLAGSET(KeyState, 0x01))
  769. {
  770. Cancel = true;
  771. }
  772. if ((Now() - FDirectoryReadingStart) >= DirectoryReadingProgressDelay)
  773. {
  774. FProgressTitle = FMTLOAD(DIRECTORY_READING_PROGRESS, (Progress));
  775. UpdateAppTitle();
  776. }
  777. }
  778. }
  779. //---------------------------------------------------------------------------
  780. void __fastcall TTerminalManager::TerminalInformation(
  781. TTerminal * Terminal, const AnsiString & Str, bool /*Status*/, bool Active)
  782. {
  783. if (Active)
  784. {
  785. if (Terminal->Status == ssOpening)
  786. {
  787. bool ShowPending = false;
  788. if (FAuthenticateForm == NULL)
  789. {
  790. FAuthenticateForm = new TAuthenticateForm(Application,
  791. Terminal->SessionData->SessionName);
  792. ShowPending = true;
  793. Busy(true);
  794. }
  795. FAuthenticateForm->Log(Str);
  796. if (ShowPending)
  797. {
  798. FAuthenticateForm->ShowAsModal();
  799. }
  800. }
  801. }
  802. else
  803. {
  804. Busy(false);
  805. SAFE_DESTROY(FAuthenticateForm);
  806. }
  807. }
  808. //---------------------------------------------------------------------------
  809. void __fastcall TTerminalManager::OperationFinished(::TFileOperation Operation,
  810. TOperationSide Side, bool Temp, const AnsiString FileName, bool Success,
  811. bool & DisconnectWhenFinished)
  812. {
  813. assert(ScpExplorer);
  814. ScpExplorer->OperationFinished(Operation, Side, Temp, FileName, Success,
  815. DisconnectWhenFinished);
  816. }
  817. //---------------------------------------------------------------------------
  818. void __fastcall TTerminalManager::OperationProgress(
  819. TFileOperationProgressType & ProgressData, TCancelStatus & Cancel)
  820. {
  821. if (ProgressData.InProgress)
  822. {
  823. FProgressTitle = FORMAT("%d%% %s",
  824. (ProgressData.OverallProgress(),
  825. TProgressForm::OperationName(ProgressData.Operation)));
  826. }
  827. else
  828. {
  829. FProgressTitle = "";
  830. }
  831. UpdateAppTitle();
  832. assert(ScpExplorer);
  833. ScpExplorer->OperationProgress(ProgressData, Cancel);
  834. }
  835. //---------------------------------------------------------------------------
  836. void __fastcall TTerminalManager::QueueEvent(TTerminalQueue * Queue, TQueueEvent Event)
  837. {
  838. TGuard Guard(FQueueSection);
  839. FQueueWithEvent = Queue;
  840. FQueueEvent = Event;
  841. }
  842. //---------------------------------------------------------------------------
  843. void __fastcall TTerminalManager::ConfigurationChange(TObject * /*Sender*/)
  844. {
  845. assert(Configuration);
  846. assert(Configuration == WinConfiguration);
  847. if (!Application->Terminated && Configuration->Logging &&
  848. (WinConfiguration->LogView == lvWindow))
  849. {
  850. if (ActiveTerminal)
  851. {
  852. RequireLogForm(LogMemo);
  853. }
  854. }
  855. else
  856. {
  857. FreeLogForm();
  858. }
  859. TTerminalQueue * Queue;
  860. for (int Index = 0; Index < Count; Index++)
  861. {
  862. assert(Terminals[Index]->Log);
  863. Terminals[Index]->Log->ReflectSettings();
  864. Queue = reinterpret_cast<TTerminalQueue *>(FQueues->Items[Index]);
  865. Queue->TransfersLimit = GUIConfiguration->QueueTransfersLimit;
  866. }
  867. if (ScpExplorer)
  868. {
  869. ScpExplorer->ConfigurationChanged();
  870. }
  871. }
  872. //---------------------------------------------------------------------------
  873. void __fastcall TTerminalManager::TerminalReady()
  874. {
  875. ScpExplorer->Terminal = ActiveTerminal;
  876. ScpExplorer->Queue = ActiveQueue;
  877. }
  878. //---------------------------------------------------------------------------
  879. TStrings * __fastcall TTerminalManager::GetTerminalList()
  880. {
  881. if (FTerminalList->Count != Count)
  882. {
  883. for (int i = 0; i < Count; i++)
  884. {
  885. AnsiString NameN;
  886. AnsiString Name = Terminals[i]->SessionData->SessionName;
  887. int Number = 1;
  888. NameN = Name;
  889. while (FTerminalList->IndexOf(NameN) >= 0)
  890. {
  891. Number++;
  892. NameN = FORMAT("%s (%d)", (Name, Number));
  893. }
  894. if (Number > 1)
  895. {
  896. Name = FORMAT("%s (%d)", (Name, Number));
  897. }
  898. FTerminalList->AddObject(Name, Terminals[i]);
  899. }
  900. }
  901. return FTerminalList;
  902. }
  903. //---------------------------------------------------------------------------
  904. int __fastcall TTerminalManager::GetActiveTerminalIndex()
  905. {
  906. return ActiveTerminal ? IndexOf(ActiveTerminal) : -1;
  907. }
  908. //---------------------------------------------------------------------------
  909. void __fastcall TTerminalManager::SetActiveTerminalIndex(int value)
  910. {
  911. ActiveTerminal = Terminals[value];
  912. }
  913. //---------------------------------------------------------------------------
  914. AnsiString __fastcall TTerminalManager::TerminalTitle(TTerminal * Terminal)
  915. {
  916. int Index = IndexOf(Terminal);
  917. assert(Index >= 0);
  918. AnsiString Result;
  919. if (Index >= 0)
  920. {
  921. Result = TerminalList->Strings[Index];
  922. }
  923. else
  924. {
  925. Result = Terminal->SessionData->SessionName;
  926. }
  927. return Result;
  928. }
  929. //---------------------------------------------------------------------------
  930. AnsiString __fastcall TTerminalManager::GetActiveTerminalTitle()
  931. {
  932. AnsiString Result = ActiveTerminal ?
  933. TerminalTitle(ActiveTerminal) : AnsiString("");
  934. return Result;
  935. }
  936. //---------------------------------------------------------------------------
  937. TTerminalQueue * __fastcall TTerminalManager::GetActiveQueue()
  938. {
  939. TTerminalQueue * Result = NULL;
  940. if (ActiveTerminal != NULL)
  941. {
  942. Result = reinterpret_cast<TTerminalQueue *>(FQueues->Items[ActiveTerminalIndex]);
  943. }
  944. return Result;
  945. }
  946. //---------------------------------------------------------------------------
  947. void __fastcall TTerminalManager::CycleTerminals(bool Forward)
  948. {
  949. int Index = ActiveTerminalIndex;
  950. Index += Forward ? 1 : -1;
  951. if (Index < 0)
  952. {
  953. Index = Count-1;
  954. }
  955. else if (Index >= Count)
  956. {
  957. Index = 0;
  958. }
  959. ActiveTerminalIndex = Index;
  960. }
  961. //---------------------------------------------------------------------------
  962. bool __fastcall TTerminalManager::CanOpenInPutty()
  963. {
  964. return (ActiveTerminal != NULL) && !GUIConfiguration->PuttyPath.Trim().IsEmpty();
  965. }
  966. //---------------------------------------------------------------------------
  967. void __fastcall TTerminalManager::OpenInPutty()
  968. {
  969. TSessionData * Data = new TSessionData("");
  970. try
  971. {
  972. Data->Assign(ActiveTerminal->SessionData);
  973. if (ActiveTerminal->TunnelLocalPortNumber != 0)
  974. {
  975. Data->ConfigureTunnel(ActiveTerminal->TunnelLocalPortNumber);
  976. }
  977. assert(ActiveTerminal != NULL);
  978. OpenSessionInPutty(GUIConfiguration->PuttyPath, Data,
  979. GUIConfiguration->PuttyPassword ? ActiveTerminal->Password : AnsiString());
  980. }
  981. __finally
  982. {
  983. delete Data;
  984. }
  985. }
  986. //---------------------------------------------------------------------------
  987. bool __fastcall TTerminalManager::NewSession()
  988. {
  989. bool Result;
  990. TSessionData * Data = new TSessionData("");
  991. try
  992. {
  993. Data->Assign(StoredSessions->DefaultSettings);
  994. if (DoLoginDialog(StoredSessions, Data, loAddSession))
  995. {
  996. if ((Data->FSProtocol == fsExternalSSH) ||
  997. (Data->FSProtocol == fsExternalSFTP))
  998. {
  999. OpenSessionInPutty(
  1000. ((Data->FSProtocol == fsExternalSSH) ?
  1001. GUIConfiguration->PuttyPath : GUIConfiguration->PSftpPath),
  1002. Data, (GUIConfiguration->PuttyPassword ? Data->Password : AnsiString()));
  1003. Result = false;
  1004. }
  1005. else
  1006. {
  1007. assert(Data->CanLogin);
  1008. TTerminalManager * Manager = TTerminalManager::Instance();
  1009. TTerminal * Terminal = Manager->NewTerminal(Data);
  1010. Manager->ActiveTerminal = Terminal;
  1011. Result = Manager->ConnectActiveTerminal();
  1012. }
  1013. }
  1014. }
  1015. __finally
  1016. {
  1017. delete Data;
  1018. }
  1019. return Result;
  1020. }
  1021. //---------------------------------------------------------------------------
  1022. void __fastcall TTerminalManager::Idle()
  1023. {
  1024. for (int Index = 0; Index < Count; Index++)
  1025. {
  1026. TTerminal * Terminal = Terminals[Index];
  1027. try
  1028. {
  1029. if (Terminal->Active)
  1030. {
  1031. Terminal->Idle();
  1032. assert(Index < FQueues->Count);
  1033. if (Index < FQueues->Count)
  1034. {
  1035. reinterpret_cast<TTerminalQueue *>(FQueues->Items[Index])->Idle();
  1036. }
  1037. }
  1038. }
  1039. catch(Exception & E)
  1040. {
  1041. if (Terminal == ActiveTerminal)
  1042. {
  1043. Terminal->ShowExtendedException(&E);
  1044. }
  1045. else
  1046. {
  1047. // we may not have inactive terminal, unless there is a explorer,
  1048. // also Idle is calls frome explorer anyway
  1049. assert(ScpExplorer != NULL);
  1050. if (ScpExplorer != NULL)
  1051. {
  1052. ScpExplorer->InactiveTerminalException(Terminal, &E);
  1053. }
  1054. if (!Terminal->Active)
  1055. {
  1056. // if session is lost, save the error message and rethrow it
  1057. // once the terminal gets activated
  1058. FTerminationMessages->Strings[Index] = E.Message;
  1059. }
  1060. }
  1061. }
  1062. }
  1063. TTerminalQueue * QueueWithEvent;
  1064. TQueueEvent QueueEvent;
  1065. {
  1066. TGuard Guard(FQueueSection);
  1067. QueueWithEvent = FQueueWithEvent;
  1068. FQueueWithEvent = NULL;
  1069. QueueEvent = FQueueEvent;
  1070. }
  1071. if (QueueWithEvent != NULL)
  1072. {
  1073. int Index = FQueues->IndexOf(QueueWithEvent);
  1074. // the session may not exist anymore
  1075. if (Index >= 0)
  1076. {
  1077. TTerminal * Terminal = Terminals[Index];
  1078. // we can hardly have a queue event without explorer
  1079. assert(ScpExplorer != NULL);
  1080. if (ScpExplorer != NULL)
  1081. {
  1082. ScpExplorer->QueueEvent(Terminal, QueueWithEvent, QueueEvent);
  1083. }
  1084. }
  1085. }
  1086. }