Terminal.cpp 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "Terminal.h"
  5. #include <SysUtils.hpp>
  6. #include <FileCtrl.hpp>
  7. #include "Common.h"
  8. #include "FileBuffer.h"
  9. #include "FileSystems.h"
  10. #include "Interface.h"
  11. #include "RemoteFiles.h"
  12. #include "ScpFileSystem.h"
  13. #include "SftpFileSystem.h"
  14. #include "TextsCore.h"
  15. //---------------------------------------------------------------------------
  16. #pragma package(smart_init)
  17. //---------------------------------------------------------------------------
  18. #define COMMAND_ERROR_ARI(MESSAGE, REPEAT) \
  19. { \
  20. int Result = CommandError(&E, MESSAGE, qaRetry | qaSkip | qaAbort); \
  21. switch (Result) { \
  22. case qaRetry: { REPEAT; } break; \
  23. case qaAbort: Abort(); \
  24. } \
  25. }
  26. #define FILE_OPERATION_LOOP_EX(ALLOW_SKIP, MESSAGE, OPERATION) \
  27. FILE_OPERATION_LOOP_CUSTOM(this, ALLOW_SKIP, MESSAGE, OPERATION)
  28. //---------------------------------------------------------------------------
  29. __fastcall TTerminal::TTerminal(): TSecureShell()
  30. {
  31. FFiles = new TRemoteDirectory(this);
  32. FExceptionOnFail = 0;
  33. FInTransaction = 0;
  34. FReadCurrentDirectoryPending = false;
  35. FReadDirectoryPending = false;
  36. FUserGroupsLookedup = False;
  37. FUserGroups = new TUserGroupsList();
  38. FOnProgress = NULL;
  39. FOnFinished = NULL;
  40. FOnDeleteLocalFile = NULL;
  41. FAdditionalInfo = NULL;
  42. FUseBusyCursor = True;
  43. FLockDirectory = "";
  44. FDirectoryCache = new TRemoteDirectoryCache();
  45. FDirectoryChangesCache = NULL;
  46. FFSProtocol = cfsUnknown;
  47. }
  48. //---------------------------------------------------------------------------
  49. __fastcall TTerminal::~TTerminal()
  50. {
  51. if (SessionData->CacheDirectoryChanges && SessionData->PreserveDirectoryChanges &&
  52. (FDirectoryChangesCache != NULL))
  53. {
  54. Configuration->SaveDirectoryChangesCache(SessionData->SessionKey,
  55. FDirectoryChangesCache);
  56. }
  57. SAFE_DESTROY(FFileSystem);
  58. delete FFiles;
  59. delete FUserGroups;
  60. delete FDirectoryCache;
  61. delete FDirectoryChangesCache;
  62. delete FAdditionalInfo;
  63. }
  64. //---------------------------------------------------------------------------
  65. void __fastcall TTerminal::KeepAlive()
  66. {
  67. if (SessionData->PingType == ptDummyCommand)
  68. {
  69. LogEvent("Executing dummy command to keep session alive.");
  70. assert(Active);
  71. assert(FFileSystem != NULL);
  72. try
  73. {
  74. FFileSystem->KeepAlive();
  75. }
  76. catch(Exception & E)
  77. {
  78. if (Active)
  79. {
  80. HandleExtendedException(&E, this);
  81. }
  82. else
  83. {
  84. throw;
  85. }
  86. }
  87. }
  88. else
  89. {
  90. TSecureShell::KeepAlive();
  91. }
  92. }
  93. //---------------------------------------------------------------------------
  94. bool __fastcall TTerminal::IsAbsolutePath(const AnsiString Path)
  95. {
  96. return !Path.IsEmpty() && Path[1] == '/';
  97. }
  98. //---------------------------------------------------------------------------
  99. AnsiString __fastcall TTerminal::ExpandFileName(AnsiString Path,
  100. const AnsiString BasePath)
  101. {
  102. Path = UnixExcludeTrailingBackslash(Path);
  103. if (!IsAbsolutePath(Path) && !BasePath.IsEmpty())
  104. {
  105. // TODO: Handle more complicated cases like "../../xxx"
  106. if (Path == "..")
  107. {
  108. Path = UnixExcludeTrailingBackslash(UnixExtractFilePath(
  109. UnixExcludeTrailingBackslash(BasePath)));
  110. }
  111. else
  112. {
  113. Path = UnixIncludeTrailingBackslash(BasePath) + Path;
  114. }
  115. }
  116. return Path;
  117. }
  118. //---------------------------------------------------------------------------
  119. AnsiString __fastcall TTerminal::GetProtocolName()
  120. {
  121. assert(FFileSystem);
  122. return FFileSystem->ProtocolName;
  123. }
  124. //---------------------------------------------------------------------------
  125. void __fastcall TTerminal::Close()
  126. {
  127. // file system cannot be destoryed here, moved to destructor
  128. TSecureShell::Close();
  129. }
  130. //---------------------------------------------------------------------------
  131. void __fastcall TTerminal::Open()
  132. {
  133. TSecureShell::Open();
  134. assert(!FFileSystem);
  135. if ((SessionData->FSProtocol == fsSCPonly) ||
  136. (SessionData->FSProtocol == fsSFTP && SshFallbackCmd()))
  137. {
  138. FFSProtocol = cfsSCP;
  139. FFileSystem = new TSCPFileSystem(this);
  140. LogEvent("Using SCP protocol.");
  141. }
  142. else
  143. {
  144. FFSProtocol = cfsSFTP;
  145. FFileSystem = new TSFTPFileSystem(this);
  146. LogEvent("Using SFTP protocol.");
  147. }
  148. if (SessionData->CacheDirectoryChanges)
  149. {
  150. FDirectoryChangesCache = new TRemoteDirectoryChangesCache();
  151. if (SessionData->PreserveDirectoryChanges)
  152. {
  153. Configuration->LoadDirectoryChangesCache(SessionData->SessionKey,
  154. FDirectoryChangesCache);
  155. }
  156. }
  157. }
  158. //---------------------------------------------------------------------------
  159. bool __fastcall TTerminal::GetIsCapable(TFSCapability Capability) const
  160. {
  161. assert(FFileSystem);
  162. return FFileSystem->IsCapable(Capability);
  163. }
  164. //---------------------------------------------------------------------------
  165. TStrings * __fastcall TTerminal::GetAdditionalInfo()
  166. {
  167. bool Initial = (FAdditionalInfo == NULL);
  168. if (Initial)
  169. {
  170. FAdditionalInfo = new TStringList();
  171. }
  172. assert(FFileSystem);
  173. FFileSystem->AdditionalInfo(FAdditionalInfo, Initial);
  174. return FAdditionalInfo;
  175. }
  176. //---------------------------------------------------------------------------
  177. AnsiString __fastcall TTerminal::AbsolutePath(AnsiString Path)
  178. {
  179. return FFileSystem->AbsolutePath(Path);
  180. }
  181. //---------------------------------------------------------------------------
  182. void __fastcall TTerminal::ReactOnCommand(int /*TFSCommand*/ Cmd)
  183. {
  184. bool ChangesDirectory = false;
  185. bool ModifiesFiles = false;
  186. switch ((TFSCommand)Cmd) {
  187. case fsChangeDirectory:
  188. case fsHomeDirectory:
  189. ChangesDirectory = true;
  190. break;
  191. case fsCopyToRemote:
  192. case fsDeleteFile:
  193. case fsRenameFile:
  194. case fsCreateDirectory:
  195. case fsChangeMode:
  196. case fsChangeGroup:
  197. case fsChangeOwner:
  198. case fsChangeProperties:
  199. case fsAnyCommand:
  200. ModifiesFiles = true;
  201. break;
  202. }
  203. if (ChangesDirectory)
  204. {
  205. if (!FInTransaction)
  206. {
  207. ReadCurrentDirectory();
  208. ReadDirectory(false);
  209. }
  210. else
  211. {
  212. FReadCurrentDirectoryPending = true;
  213. FReadDirectoryPending = true;
  214. }
  215. }
  216. else
  217. if (ModifiesFiles)
  218. {
  219. if (!FInTransaction) ReadDirectory(true);
  220. else FReadDirectoryPending = true;
  221. }
  222. }
  223. //---------------------------------------------------------------------------
  224. void __fastcall TTerminal::TerminalError(AnsiString Msg)
  225. {
  226. TerminalError(NULL, Msg);
  227. }
  228. //---------------------------------------------------------------------------
  229. void __fastcall TTerminal::TerminalError(Exception * E, AnsiString Msg)
  230. {
  231. throw ETerminal(E, Msg);
  232. }
  233. //---------------------------------------------------------------------------
  234. int __fastcall TTerminal::FileOperationLoop(TFileOperationEvent CallBackFunc,
  235. TFileOperationProgressType * OperationProgress, bool AllowSkip,
  236. const AnsiString Message, void * Param1, void * Param2)
  237. {
  238. assert(CallBackFunc);
  239. int Result;
  240. FILE_OPERATION_LOOP_EX
  241. (
  242. AllowSkip, Message,
  243. Result = CallBackFunc(Param1, Param2);
  244. );
  245. return Result;
  246. }
  247. //---------------------------------------------------------------------------
  248. AnsiString __fastcall TTerminal::TranslateLockedPath(AnsiString Path, bool Lock)
  249. {
  250. if (!SessionData->LockInHome || Path.IsEmpty() || (Path[1] != '/'))
  251. return Path;
  252. if (Lock)
  253. {
  254. if (Path.SubString(1, FLockDirectory.Length()) == FLockDirectory)
  255. {
  256. Path.Delete(1, FLockDirectory.Length());
  257. if (Path.IsEmpty()) Path = "/";
  258. }
  259. }
  260. else
  261. {
  262. Path = UnixExcludeTrailingBackslash(FLockDirectory + Path);
  263. }
  264. return Path;
  265. }
  266. //---------------------------------------------------------------------------
  267. void __fastcall TTerminal::ClearCaches()
  268. {
  269. FDirectoryCache->Clear();
  270. if (FDirectoryChangesCache != NULL)
  271. {
  272. FDirectoryChangesCache->Clear();
  273. }
  274. }
  275. //---------------------------------------------------------------------------
  276. void __fastcall TTerminal::SetCurrentDirectory(AnsiString value)
  277. {
  278. assert(FFileSystem);
  279. value = TranslateLockedPath(value, false);
  280. if (value != FFileSystem->CurrentDirectory)
  281. {
  282. ChangeDirectory(value);
  283. }
  284. }
  285. //---------------------------------------------------------------------------
  286. AnsiString __fastcall TTerminal::GetCurrentDirectory()
  287. {
  288. if (FFileSystem)
  289. {
  290. FCurrentDirectory = FFileSystem->CurrentDirectory;
  291. if (FCurrentDirectory.IsEmpty())
  292. {
  293. ReadCurrentDirectory();
  294. }
  295. }
  296. return TranslateLockedPath(FCurrentDirectory, true);
  297. }
  298. //---------------------------------------------------------------------------
  299. AnsiString __fastcall TTerminal::PeekCurrentDirectory()
  300. {
  301. if (FFileSystem)
  302. {
  303. FCurrentDirectory = FFileSystem->CurrentDirectory;
  304. }
  305. return TranslateLockedPath(FCurrentDirectory, true);
  306. }
  307. //---------------------------------------------------------------------------
  308. TUserGroupsList * __fastcall TTerminal::GetUserGroups()
  309. {
  310. assert(FFileSystem);
  311. if (!FUserGroupsLookedup && SessionData->LookupUserGroups &&
  312. IsCapable[fcUserGroupListing])
  313. {
  314. LookupUserGroups();
  315. }
  316. return FUserGroups;
  317. }
  318. //---------------------------------------------------------------------------
  319. AnsiString __fastcall TTerminal::GetUserName() const
  320. {
  321. // in future might be implemented to detect username similar to GetUserGroups
  322. return SessionData->UserName;
  323. }
  324. //---------------------------------------------------------------------------
  325. bool __fastcall TTerminal::GetAreCachesEmpty() const
  326. {
  327. return FDirectoryCache->IsEmpty &&
  328. ((FDirectoryChangesCache == NULL) || FDirectoryChangesCache->IsEmpty);
  329. }
  330. //---------------------------------------------------------------------------
  331. void __fastcall TTerminal::DoChangeDirectory()
  332. {
  333. if (FOnChangeDirectory)
  334. {
  335. FOnChangeDirectory(this);
  336. }
  337. }
  338. //---------------------------------------------------------------------------
  339. void __fastcall TTerminal::DoReadDirectory(bool ReloadOnly)
  340. {
  341. if (FOnReadDirectory)
  342. {
  343. FOnReadDirectory(this, ReloadOnly);
  344. }
  345. }
  346. //---------------------------------------------------------------------------
  347. void __fastcall TTerminal::DoStartReadDirectory()
  348. {
  349. if (FOnStartReadDirectory)
  350. {
  351. FOnStartReadDirectory(this);
  352. }
  353. }
  354. //---------------------------------------------------------------------------
  355. void __fastcall TTerminal::BeginTransaction()
  356. {
  357. if (!FInTransaction)
  358. {
  359. FReadCurrentDirectoryPending = false;
  360. FReadDirectoryPending = false;
  361. }
  362. FInTransaction++;
  363. }
  364. //---------------------------------------------------------------------------
  365. void __fastcall TTerminal::EndTransaction()
  366. {
  367. // it connection was closed due to fatal error during transaction, do nothing
  368. if (Active)
  369. {
  370. if (!FInTransaction)
  371. TerminalError("Can't end transaction, not in transaction");
  372. assert(FInTransaction > 0);
  373. FInTransaction--;
  374. if (FInTransaction == 0)
  375. {
  376. try
  377. {
  378. if (FReadCurrentDirectoryPending) ReadCurrentDirectory();
  379. if (FReadDirectoryPending) ReadDirectory(!FReadCurrentDirectoryPending);
  380. }
  381. __finally
  382. {
  383. FReadCurrentDirectoryPending = false;
  384. FReadDirectoryPending = false;
  385. }
  386. }
  387. }
  388. }
  389. //---------------------------------------------------------------------------
  390. void __fastcall TTerminal::SetExceptionOnFail(bool value)
  391. {
  392. if (value) FExceptionOnFail++;
  393. else
  394. {
  395. if (FExceptionOnFail == 0)
  396. throw Exception("ExceptionOnFail is already zero.");
  397. FExceptionOnFail--;
  398. }
  399. }
  400. //---------------------------------------------------------------------------
  401. bool __fastcall TTerminal::GetExceptionOnFail() const
  402. {
  403. return (bool)(FExceptionOnFail > 0);
  404. }
  405. //---------------------------------------------------------------------------
  406. void __fastcall TTerminal::CommandError(Exception * E, const AnsiString Msg)
  407. {
  408. CommandError(E, Msg, 0);
  409. }
  410. //---------------------------------------------------------------------------
  411. int __fastcall TTerminal::CommandError(Exception * E, const AnsiString Msg,
  412. int Answers)
  413. {
  414. int Result = 0;
  415. if (E && E->InheritsFrom(__classid(EFatal)))
  416. {
  417. FatalError(E, Msg);
  418. }
  419. else if (E && E->InheritsFrom(__classid(EAbort)))
  420. {
  421. // resent EAbort exception
  422. Abort();
  423. }
  424. else if (ExceptionOnFail)
  425. {
  426. throw ECommand(E, Msg);
  427. }
  428. else if (!Answers)
  429. {
  430. ECommand * ECmd = new ECommand(E, Msg);
  431. try
  432. {
  433. ShowExtendedException(ECmd, this);
  434. }
  435. __finally
  436. {
  437. delete ECmd;
  438. }
  439. }
  440. else
  441. {
  442. Result = DoQueryUser(Msg, E, Answers, qpAllowContinueOnError);
  443. }
  444. return Result;
  445. }
  446. //---------------------------------------------------------------------------
  447. bool __fastcall TTerminal::HandleException(Exception * E)
  448. {
  449. if (ExceptionOnFail)
  450. {
  451. return false;
  452. }
  453. else
  454. {
  455. HandleExtendedException(E, this);
  456. return true;
  457. }
  458. }
  459. //---------------------------------------------------------------------------
  460. void __fastcall TTerminal::CloseOnCompletion(const AnsiString Message)
  461. {
  462. LogEvent("Closing session after completed operation (as requested by user)");
  463. Close();
  464. throw ESshTerminate(NULL,
  465. Message.IsEmpty() ? LoadStr(CLOSED_ON_COMPLETION) : Message);
  466. }
  467. //---------------------------------------------------------------------------
  468. int __fastcall TTerminal::ConfirmFileOverwrite(const AnsiString FileName,
  469. const TOverwriteFileParams * FileParams, int Answers, int Params)
  470. {
  471. AnsiString Message = FMTLOAD(FILE_OVERWRITE, (FileName));
  472. if (FileParams)
  473. {
  474. Message = FMTLOAD(FILE_OVERWRITE_DETAILS, (Message,
  475. IntToStr(FileParams->SourceSize),
  476. FormatDateTime("ddddd tt", FileParams->SourceTimestamp),
  477. IntToStr(FileParams->DestSize),
  478. FormatDateTime("ddddd tt", FileParams->DestTimestamp)));
  479. }
  480. return DoQueryUser(Message, Answers, Params);
  481. }
  482. //---------------------------------------------------------------------------
  483. void __fastcall TTerminal::FileModified(const TRemoteFile * File,
  484. const AnsiString FileName)
  485. {
  486. if (SessionData->CacheDirectories)
  487. {
  488. if ((File != NULL) && (File->Directory != NULL))
  489. {
  490. if (File->IsDirectory)
  491. {
  492. // do not use UnixIncludeTrailingBackslash(CurrentDirectory)
  493. FDirectoryCache->ClearFileList(
  494. File->Directory->FullDirectory + File->FileName, true);
  495. }
  496. FDirectoryCache->ClearFileList(File->Directory->Directory, false);
  497. }
  498. else if (!FileName.IsEmpty())
  499. {
  500. AnsiString Directory = UnixExtractFilePath(FileName);
  501. FDirectoryCache->ClearFileList(
  502. !Directory.IsEmpty() ? Directory : CurrentDirectory, false);
  503. }
  504. }
  505. }
  506. //---------------------------------------------------------------------------
  507. void __fastcall TTerminal::DirectoryModified(const AnsiString UnlockedPath, bool SubDirs)
  508. {
  509. FDirectoryCache->ClearFileList(TranslateLockedPath(UnlockedPath, true),
  510. SubDirs);
  511. }
  512. //---------------------------------------------------------------------------
  513. void __fastcall TTerminal::ReloadDirectory()
  514. {
  515. if (SessionData->CacheDirectories)
  516. {
  517. FDirectoryCache->ClearFileList(CurrentDirectory, false);
  518. }
  519. if (SessionData->CacheDirectoryChanges)
  520. {
  521. assert(FDirectoryChangesCache != NULL);
  522. FDirectoryChangesCache->ClearDirectoryChange(CurrentDirectory);
  523. }
  524. ReadCurrentDirectory();
  525. FReadCurrentDirectoryPending = false;
  526. ReadDirectory(True);
  527. FReadDirectoryPending = false;
  528. }
  529. //---------------------------------------------------------------------------
  530. void __fastcall TTerminal::EnsureNonExistence(const AnsiString FileName)
  531. {
  532. // if filename doesn't contain path, we check for existence of file
  533. if ((UnixExtractFileDir(FileName) == FileName) &&
  534. UnixComparePaths(CurrentDirectory, FFiles->Directory))
  535. {
  536. TRemoteFile *File = FFiles->FindFile(FileName);
  537. if (File)
  538. {
  539. if (File->IsDirectory) throw ECommand(NULL, FMTLOAD(RENAME_CREATE_DIR_EXISTS, (FileName)));
  540. else throw ECommand(NULL, FMTLOAD(RENAME_CREATE_FILE_EXISTS, (FileName)));
  541. }
  542. }
  543. }
  544. //---------------------------------------------------------------------------
  545. void __fastcall TTerminal::DoStartup()
  546. {
  547. LogEvent("Doing startup conversation with host.");
  548. BeginTransaction();
  549. try
  550. {
  551. UpdateStatus(sshStartup);
  552. // Make sure that directory would be loaded at last
  553. FReadCurrentDirectoryPending = true;
  554. FReadDirectoryPending = true;
  555. FFileSystem->DoStartup();
  556. if (SessionData->LookupUserGroups && IsCapable[fcUserGroupListing])
  557. {
  558. LookupUserGroups();
  559. }
  560. UpdateStatus(sshOpenDirectory);
  561. if (!SessionData->RemoteDirectory.IsEmpty())
  562. {
  563. ChangeDirectory(SessionData->RemoteDirectory);
  564. }
  565. }
  566. __finally
  567. {
  568. EndTransaction();
  569. }
  570. LogEvent("Startup conversation with host finished.");
  571. UpdateStatus(sshReady);
  572. }
  573. //---------------------------------------------------------------------------
  574. void __fastcall TTerminal::ReadCurrentDirectory()
  575. {
  576. assert(FFileSystem);
  577. try
  578. {
  579. LogEvent("Getting current directory name.");
  580. AnsiString OldDirectory = FFileSystem->CurrentDirectory;
  581. FFileSystem->ReadCurrentDirectory();
  582. ReactOnCommand(fsCurrentDirectory);
  583. if (SessionData->CacheDirectoryChanges)
  584. {
  585. assert(FDirectoryChangesCache != NULL);
  586. FDirectoryChangesCache->AddDirectoryChange(OldDirectory,
  587. FLastDirectoryChange, CurrentDirectory);
  588. }
  589. if (OldDirectory.IsEmpty())
  590. {
  591. FLockDirectory = (SessionData->LockInHome ?
  592. FFileSystem->CurrentDirectory : AnsiString(""));
  593. }
  594. if (OldDirectory != FFileSystem->CurrentDirectory) DoChangeDirectory();
  595. }
  596. catch (Exception &E)
  597. {
  598. CommandError(&E, LoadStr(READ_CURRENT_DIR_ERROR));
  599. }
  600. }
  601. //---------------------------------------------------------------------------
  602. void __fastcall TTerminal::ReadDirectory(bool ReloadOnly)
  603. {
  604. TRemoteFileList * CachedFileList = NULL;
  605. if (SessionData->CacheDirectories)
  606. {
  607. CachedFileList = FDirectoryCache->GetFileList(CurrentDirectory);
  608. }
  609. if (CachedFileList)
  610. {
  611. if (ReloadOnly)
  612. {
  613. LogEvent("Cached directory not reloaded.");
  614. }
  615. else
  616. {
  617. DoStartReadDirectory();
  618. try
  619. {
  620. CachedFileList->DuplicateTo(FFiles);
  621. }
  622. __finally
  623. {
  624. DoReadDirectory(ReloadOnly);
  625. }
  626. LogEvent("Directory content loaded from cache.");
  627. }
  628. }
  629. else
  630. {
  631. DoStartReadDirectory();
  632. FFiles->Directory = CurrentDirectory;
  633. try
  634. {
  635. try
  636. {
  637. CustomReadDirectory(FFiles);
  638. }
  639. __finally
  640. {
  641. // this must be called before error is displayed, otherwise
  642. // TUnixDirView would be drawn with invalid data (it keeps reference
  643. // to already destoroyed old listing)
  644. DoReadDirectory(ReloadOnly);
  645. if (Active)
  646. {
  647. if (SessionData->CacheDirectories)
  648. {
  649. FDirectoryCache->AddFileList(FFiles);
  650. }
  651. }
  652. }
  653. }
  654. catch (Exception &E)
  655. {
  656. CommandError(&E, FmtLoadStr(LIST_DIR_ERROR, ARRAYOFCONST((FFiles->Directory))));
  657. }
  658. }
  659. }
  660. //---------------------------------------------------------------------------
  661. void __fastcall TTerminal::CustomReadDirectory(TRemoteFileList * FileList)
  662. {
  663. assert(FileList);
  664. assert(FFileSystem);
  665. FFileSystem->ReadDirectory(FileList);
  666. ReactOnCommand(fsListDirectory);
  667. }
  668. //---------------------------------------------------------------------------
  669. TRemoteFileList * TTerminal::ReadDirectoryListing(AnsiString Directory)
  670. {
  671. TRemoteFileList * FileList;
  672. try
  673. {
  674. FileList = new TRemoteFileList();
  675. try
  676. {
  677. FileList->Directory = Directory;
  678. AnsiString Directory = UnixIncludeTrailingBackslash(Directory);
  679. ExceptionOnFail = true;
  680. try
  681. {
  682. ReadDirectory(FileList);
  683. }
  684. __finally
  685. {
  686. ExceptionOnFail = false;
  687. }
  688. }
  689. catch(...)
  690. {
  691. delete FileList;
  692. FileList = NULL;
  693. throw;
  694. }
  695. }
  696. catch(Exception & E)
  697. {
  698. COMMAND_ERROR_ARI
  699. (
  700. "",
  701. FileList = ReadDirectoryListing(Directory);
  702. );
  703. }
  704. return FileList;
  705. }
  706. //---------------------------------------------------------------------------
  707. void __fastcall TTerminal::ProcessDirectory(const AnsiString DirName,
  708. TProcessFileEvent CallBackFunc, void * Param)
  709. {
  710. TRemoteFileList * FileList = ReadDirectoryListing(DirName);
  711. // skip if directory listing fails and user selects "skip"
  712. if (FileList)
  713. {
  714. try
  715. {
  716. AnsiString Directory = UnixIncludeTrailingBackslash(DirName);
  717. TRemoteFile * File;
  718. for (int Index = 0; Index < FileList->Count; Index++)
  719. {
  720. File = FileList->Files[Index];
  721. if (!File->IsParentDirectory && !File->IsThisDirectory)
  722. {
  723. CallBackFunc(Directory + File->FileName, File, Param);
  724. }
  725. }
  726. }
  727. __finally
  728. {
  729. delete FileList;
  730. }
  731. }
  732. }
  733. //---------------------------------------------------------------------------
  734. void __fastcall TTerminal::ReadDirectory(TRemoteFileList * FileList)
  735. {
  736. try
  737. {
  738. CustomReadDirectory(FileList);
  739. }
  740. catch (Exception &E)
  741. {
  742. CommandError(&E, FmtLoadStr(LIST_DIR_ERROR, ARRAYOFCONST((FileList->Directory))));
  743. }
  744. }
  745. //---------------------------------------------------------------------------
  746. void __fastcall TTerminal::ReadSymlink(TRemoteFile * SymlinkFile,
  747. TRemoteFile *& File)
  748. {
  749. assert(FFileSystem);
  750. try
  751. {
  752. LogEvent(FORMAT("Reading symlink \"%s\".", (SymlinkFile->FileName)));
  753. FFileSystem->ReadSymlink(SymlinkFile, File);
  754. ReactOnCommand(fsReadSymlink);
  755. }
  756. catch (Exception &E)
  757. {
  758. CommandError(&E, FMTLOAD(READ_SYMLINK_ERROR, (SymlinkFile->FileName)));
  759. }
  760. }
  761. //---------------------------------------------------------------------------
  762. void __fastcall TTerminal::ReadFile(const AnsiString FileName,
  763. TRemoteFile *& File)
  764. {
  765. assert(FFileSystem);
  766. File = NULL;
  767. try
  768. {
  769. LogEvent(FORMAT("Listing file \"%s\".", (FileName)));
  770. FFileSystem->ReadFile(FileName, File);
  771. ReactOnCommand(fsListFile);
  772. }
  773. catch (Exception &E)
  774. {
  775. if (File) delete File;
  776. File = NULL;
  777. CommandError(&E, FMTLOAD(LIST_DIR_ERROR, (FileName)));
  778. }
  779. }
  780. //---------------------------------------------------------------------------
  781. bool __fastcall TTerminal::ProcessFiles(TStrings * FileList,
  782. TFileOperation Operation, TProcessFileEvent ProcessFile, void * Param,
  783. TOperationSide Side)
  784. {
  785. assert(FFileSystem);
  786. assert(FileList);
  787. bool Result = false;
  788. bool DisconnectWhenComplete = false;
  789. try
  790. {
  791. TFileOperationProgressType Progress(FOnProgress, FOnFinished);
  792. Progress.Start(Operation, Side, FileList->Count);
  793. FOperationProgress = &Progress;
  794. try
  795. {
  796. BeginTransaction();
  797. try
  798. {
  799. int Index = 0;
  800. AnsiString FileName;
  801. bool Success;
  802. while ((Index < FileList->Count) && (Progress.Cancel == csContinue))
  803. {
  804. FileName = FileList->Strings[Index];
  805. try
  806. {
  807. Success = false;
  808. ProcessFile(FileName, (TRemoteFile *)FileList->Objects[Index], Param);
  809. Success = true;
  810. }
  811. __finally
  812. {
  813. AnsiString FileNameOnly = (Side == osRemote) ?
  814. UnixExtractFileName(FileName) : ExtractFileName(FileName);
  815. Progress.Finish(FileNameOnly, Success, DisconnectWhenComplete);
  816. }
  817. Index++;
  818. }
  819. }
  820. __finally
  821. {
  822. EndTransaction();
  823. }
  824. if (Progress.Cancel == csContinue)
  825. {
  826. Result = true;
  827. }
  828. }
  829. __finally
  830. {
  831. FOperationProgress = NULL;
  832. Progress.Stop();
  833. }
  834. }
  835. catch (...)
  836. {
  837. DisconnectWhenComplete = false;
  838. // this was missing here. was it by purpose?
  839. // without it any error message is lost
  840. throw;
  841. }
  842. if (DisconnectWhenComplete)
  843. {
  844. CloseOnCompletion();
  845. }
  846. return Result;
  847. }
  848. //---------------------------------------------------------------------------
  849. void __fastcall TTerminal::DeleteFile(AnsiString FileName,
  850. const TRemoteFile * File, void * Recursive)
  851. {
  852. if (FileName.IsEmpty() && File)
  853. {
  854. FileName = File->FileName;
  855. }
  856. if (OperationProgress && OperationProgress->Operation == foDelete)
  857. {
  858. if (OperationProgress->Cancel != csContinue) Abort();
  859. OperationProgress->SetFile(FileName);
  860. }
  861. LogEvent(FORMAT("Deleting file \"%s\".", (FileName)));
  862. if (File) FileModified(File, FileName);
  863. DoDeleteFile(FileName, File, Recursive);
  864. ReactOnCommand(fsDeleteFile);
  865. }
  866. //---------------------------------------------------------------------------
  867. void __fastcall TTerminal::DoDeleteFile(const AnsiString FileName,
  868. const TRemoteFile * File, void * Recursive)
  869. {
  870. try
  871. {
  872. assert(FFileSystem);
  873. // 'File' parameter: SFTPFileSystem needs to know if file is file or directory
  874. FFileSystem->DeleteFile(FileName, File,
  875. Recursive ? *((bool*)Recursive) : true);
  876. }
  877. catch(Exception & E)
  878. {
  879. COMMAND_ERROR_ARI
  880. (
  881. FMTLOAD(DELETE_FILE_ERROR, (FileName)),
  882. DoDeleteFile(FileName, File, Recursive)
  883. );
  884. }
  885. }
  886. //---------------------------------------------------------------------------
  887. bool __fastcall TTerminal::DeleteFiles(TStrings * FilesToDelete, bool * Recursive)
  888. {
  889. return ProcessFiles(FilesToDelete, foDelete, DeleteFile, Recursive);
  890. }
  891. //---------------------------------------------------------------------------
  892. void __fastcall TTerminal::DeleteLocalFile(AnsiString FileName,
  893. const TRemoteFile * /*File*/, void * /*Param*/)
  894. {
  895. if (OnDeleteLocalFile == NULL)
  896. {
  897. if (!RecursiveDeleteFile(FileName, false))
  898. {
  899. throw Exception(FMTLOAD(DELETE_FILE_ERROR, (FileName)));
  900. }
  901. }
  902. else
  903. {
  904. OnDeleteLocalFile(FileName);
  905. }
  906. }
  907. //---------------------------------------------------------------------------
  908. bool __fastcall TTerminal::DeleteLocalFiles(TStrings * FileList)
  909. {
  910. return ProcessFiles(FileList, foDelete, DeleteLocalFile, NULL, osLocal);
  911. }
  912. //---------------------------------------------------------------------------
  913. void __fastcall TTerminal::CustomCommandOnFile(AnsiString FileName,
  914. const TRemoteFile * File, void * AParams)
  915. {
  916. TCustomCommandParams * Params = ((TCustomCommandParams *)AParams);
  917. if (FileName.IsEmpty() && File)
  918. {
  919. FileName = File->FileName;
  920. }
  921. if (OperationProgress && OperationProgress->Operation == foCustomCommand)
  922. {
  923. if (OperationProgress->Cancel != csContinue) Abort();
  924. OperationProgress->SetFile(FileName);
  925. }
  926. LogEvent(FORMAT("Executing custom command \"%s\" (%d) on file \"%s\".",
  927. (Params->Command, Params->Params, FileName)));
  928. if (File) FileModified(File, FileName);
  929. DoCustomCommandOnFile(FileName, File, Params->Command, Params->Params);
  930. ReactOnCommand(fsAnyCommand);
  931. }
  932. //---------------------------------------------------------------------------
  933. void __fastcall TTerminal::DoCustomCommandOnFile(AnsiString FileName,
  934. const TRemoteFile * File, AnsiString Command, int Params)
  935. {
  936. try
  937. {
  938. assert(FFileSystem);
  939. FFileSystem->CustomCommandOnFile(FileName, File, Command, Params);
  940. }
  941. catch(Exception & E)
  942. {
  943. COMMAND_ERROR_ARI
  944. (
  945. FMTLOAD(CUSTOM_COMMAND_ERROR, (Command, FileName)),
  946. DoCustomCommandOnFile(FileName, File, Command, Params)
  947. );
  948. }
  949. }
  950. //---------------------------------------------------------------------------
  951. void __fastcall TTerminal::CustomCommandOnFiles(AnsiString Command,
  952. int Params, TStrings * Files)
  953. {
  954. TCustomCommandParams AParams;
  955. AParams.Command = Command;
  956. AParams.Params = Params;
  957. ProcessFiles(Files, foCustomCommand, CustomCommandOnFile, &AParams);
  958. }
  959. //---------------------------------------------------------------------------
  960. void __fastcall TTerminal::ChangeFileProperties(AnsiString FileName,
  961. const TRemoteFile * File, /*const TRemoteProperties*/ void * Properties)
  962. {
  963. TRemoteProperties * RProperties = (TRemoteProperties *)Properties;
  964. assert(RProperties && !RProperties->Valid.Empty());
  965. if (FileName.IsEmpty() && File)
  966. {
  967. FileName = File->FileName;
  968. }
  969. if (OperationProgress && OperationProgress->Operation == foSetProperties)
  970. {
  971. if (OperationProgress->Cancel != csContinue) Abort();
  972. OperationProgress->SetFile(FileName);
  973. }
  974. if (IsLogging())
  975. {
  976. LogEvent(FORMAT("Changing properties of \"%s\" (%s)",
  977. (FileName, BooleanToEngStr(RProperties->Recursive))));
  978. if (RProperties->Valid.Contains(vpRights))
  979. {
  980. LogEvent(FORMAT(" - mode: \"%s\"", (RProperties->Rights.ModeStr)));
  981. }
  982. if (RProperties->Valid.Contains(vpGroup))
  983. {
  984. LogEvent(FORMAT(" - group: \"%s\"", (RProperties->Group)));
  985. }
  986. if (RProperties->Valid.Contains(vpOwner))
  987. {
  988. LogEvent(FORMAT(" - owner: \"%s\"", (RProperties->Owner)));
  989. }
  990. }
  991. if (File) FileModified(File, FileName);
  992. DoChangeFileProperties(FileName, File, RProperties);
  993. ReactOnCommand(fsChangeProperties);
  994. }
  995. //---------------------------------------------------------------------------
  996. void __fastcall TTerminal::DoChangeFileProperties(const AnsiString FileName,
  997. const TRemoteFile * File, const TRemoteProperties * Properties)
  998. {
  999. try
  1000. {
  1001. assert(FFileSystem);
  1002. FFileSystem->ChangeFileProperties(FileName, File, Properties);
  1003. }
  1004. catch(Exception & E)
  1005. {
  1006. COMMAND_ERROR_ARI
  1007. (
  1008. FMTLOAD(CHANGE_PROPERTIES_ERROR, (FileName)),
  1009. DoChangeFileProperties(FileName, File, Properties)
  1010. );
  1011. }
  1012. }
  1013. //---------------------------------------------------------------------------
  1014. void __fastcall TTerminal::ChangeFilesProperties(TStrings * FileList,
  1015. const TRemoteProperties * Properties)
  1016. {
  1017. ProcessFiles(FileList, foSetProperties, ChangeFileProperties, (void *)Properties);
  1018. }
  1019. //---------------------------------------------------------------------------
  1020. void __fastcall TTerminal::CalculateFileSize(AnsiString FileName,
  1021. const TRemoteFile * File, /*TCalculateSizeParams*/ void * Param)
  1022. {
  1023. assert(Param);
  1024. assert(File);
  1025. if (FileName.IsEmpty() && File)
  1026. {
  1027. FileName = File->FileName;
  1028. }
  1029. if (File->IsDirectory && !File->IsSymLink)
  1030. {
  1031. LogEvent(FORMAT("Getting size of directory \"%s\"", (FileName)));
  1032. DoCalculateDirectorySize(FileName, File,
  1033. static_cast<TCalculateSizeParams*>(Param));
  1034. }
  1035. else
  1036. {
  1037. static_cast<TCalculateSizeParams*>(Param)->Size += File->Size;
  1038. }
  1039. if (OperationProgress && OperationProgress->Operation == foCalculateSize)
  1040. {
  1041. if (OperationProgress->Cancel != csContinue) Abort();
  1042. OperationProgress->SetFile(FileName);
  1043. }
  1044. }
  1045. //---------------------------------------------------------------------------
  1046. void __fastcall TTerminal::DoCalculateDirectorySize(const AnsiString FileName,
  1047. const TRemoteFile * File, TCalculateSizeParams * Params)
  1048. {
  1049. try
  1050. {
  1051. ProcessDirectory(FileName, CalculateFileSize, Params);
  1052. }
  1053. catch(Exception & E)
  1054. {
  1055. if (!Active || ((Params->Params & csIgnoreErrors) == 0))
  1056. {
  1057. COMMAND_ERROR_ARI
  1058. (
  1059. FMTLOAD(CALCULATE_SIZE_ERROR, (FileName)),
  1060. DoCalculateDirectorySize(FileName, File, Params)
  1061. );
  1062. }
  1063. }
  1064. }
  1065. //---------------------------------------------------------------------------
  1066. void __fastcall TTerminal::CalculateFilesSize(TStrings * FileList,
  1067. __int64 & Size, int Params)
  1068. {
  1069. TCalculateSizeParams Param;
  1070. Param.Size = 0;
  1071. Param.Params = Params;
  1072. ProcessFiles(FileList, foCalculateSize, CalculateFileSize, &Param);
  1073. Size = Param.Size;
  1074. }
  1075. //---------------------------------------------------------------------------
  1076. void __fastcall TTerminal::RenameFile(const AnsiString FileName,
  1077. const AnsiString NewName)
  1078. {
  1079. LogEvent(FORMAT("Renaming file \"%s\" to \"%s\".", (FileName, NewName)));
  1080. DoRenameFile(FileName, NewName);
  1081. ReactOnCommand(fsRenameFile);
  1082. }
  1083. //---------------------------------------------------------------------------
  1084. void __fastcall TTerminal::RenameFile(const TRemoteFile * File,
  1085. const AnsiString NewName, bool CheckExistence)
  1086. {
  1087. assert(File && File->Directory == FFiles);
  1088. bool Proceed = true;
  1089. // if filename doesn't contain path, we check for existence of file
  1090. if ((File->FileName != NewName) && CheckExistence &&
  1091. Configuration->ConfirmOverwriting &&
  1092. UnixComparePaths(CurrentDirectory, FFiles->Directory))
  1093. {
  1094. TRemoteFile * DuplicateFile = FFiles->FindFile(NewName);
  1095. if (DuplicateFile)
  1096. {
  1097. AnsiString QuestionFmt;
  1098. if (DuplicateFile->IsDirectory) QuestionFmt = LoadStr(DIRECTORY_OVERWRITE);
  1099. else QuestionFmt = LoadStr(FILE_OVERWRITE);
  1100. int Result;
  1101. Result = DoQueryUser(FORMAT(QuestionFmt, (NewName)),
  1102. qaYes | qaNo, qpNeverAskAgainCheck);
  1103. if (Result == qaNeverAskAgain)
  1104. {
  1105. Proceed = true;
  1106. Configuration->ConfirmOverwriting = false;
  1107. }
  1108. else
  1109. {
  1110. Proceed = (Result == qaYes);
  1111. }
  1112. }
  1113. }
  1114. if (Proceed)
  1115. {
  1116. FileModified(File, File->FileName);
  1117. RenameFile(File->FileName, NewName);
  1118. }
  1119. }
  1120. //---------------------------------------------------------------------------
  1121. void __fastcall TTerminal::DoRenameFile(const AnsiString FileName,
  1122. const AnsiString NewName)
  1123. {
  1124. try
  1125. {
  1126. assert(FFileSystem);
  1127. FFileSystem->RenameFile(FileName, NewName);
  1128. }
  1129. catch(Exception & E)
  1130. {
  1131. COMMAND_ERROR_ARI
  1132. (
  1133. FMTLOAD(RENAME_FILE_ERROR, (FileName, NewName)),
  1134. DoRenameFile(FileName, NewName)
  1135. );
  1136. }
  1137. }
  1138. //---------------------------------------------------------------------------
  1139. void __fastcall TTerminal::CreateDirectory(const AnsiString DirName,
  1140. const TRemoteProperties * Properties)
  1141. {
  1142. assert(FFileSystem);
  1143. EnsureNonExistence(DirName);
  1144. FileModified(NULL, DirName);
  1145. LogEvent(FORMAT("Creating directory \"%s\".", (DirName)));
  1146. DoCreateDirectory(DirName, Properties);
  1147. ReactOnCommand(fsCreateDirectory);
  1148. }
  1149. //---------------------------------------------------------------------------
  1150. void __fastcall TTerminal::DoCreateDirectory(const AnsiString DirName,
  1151. const TRemoteProperties * Properties)
  1152. {
  1153. try
  1154. {
  1155. assert(FFileSystem);
  1156. FFileSystem->CreateDirectory(DirName, Properties);
  1157. }
  1158. catch(Exception & E)
  1159. {
  1160. COMMAND_ERROR_ARI
  1161. (
  1162. FMTLOAD(CREATE_DIR_ERROR, (DirName)),
  1163. DoCreateDirectory(DirName, Properties)
  1164. );
  1165. }
  1166. }
  1167. //---------------------------------------------------------------------------
  1168. void __fastcall TTerminal::CreateLink(const AnsiString FileName,
  1169. const AnsiString PointTo, bool Symbolic)
  1170. {
  1171. assert(FFileSystem);
  1172. EnsureNonExistence(FileName);
  1173. if (SessionData->CacheDirectories)
  1174. {
  1175. FDirectoryCache->ClearFileList(CurrentDirectory, false);
  1176. }
  1177. LogEvent(FORMAT("Creating link \"%s\" to \"%s\" (symbolic: %s).",
  1178. (FileName, PointTo, BooleanToEngStr(Symbolic))));
  1179. DoCreateLink(FileName, PointTo, Symbolic);
  1180. ReactOnCommand(fsCreateDirectory);
  1181. }
  1182. //---------------------------------------------------------------------------
  1183. void __fastcall TTerminal::DoCreateLink(const AnsiString FileName,
  1184. const AnsiString PointTo, bool Symbolic)
  1185. {
  1186. try
  1187. {
  1188. assert(FFileSystem);
  1189. FFileSystem->CreateLink(FileName, PointTo, Symbolic);
  1190. }
  1191. catch(Exception & E)
  1192. {
  1193. COMMAND_ERROR_ARI
  1194. (
  1195. FMTLOAD(CREATE_LINK_ERROR, (FileName)),
  1196. DoCreateLink(FileName, PointTo, Symbolic);
  1197. );
  1198. }
  1199. }
  1200. //---------------------------------------------------------------------------
  1201. void __fastcall TTerminal::HomeDirectory()
  1202. {
  1203. assert(FFileSystem);
  1204. try
  1205. {
  1206. LogEvent("Changing directory to home directory.");
  1207. FFileSystem->HomeDirectory();
  1208. ReactOnCommand(fsHomeDirectory);
  1209. }
  1210. catch (Exception &E)
  1211. {
  1212. CommandError(&E, LoadStr(CHANGE_HOMEDIR_ERROR));
  1213. }
  1214. }
  1215. //---------------------------------------------------------------------------
  1216. void __fastcall TTerminal::ChangeDirectory(const AnsiString Directory)
  1217. {
  1218. assert(FFileSystem);
  1219. try
  1220. {
  1221. AnsiString CachedDirectory;
  1222. assert(!SessionData->CacheDirectoryChanges || (FDirectoryChangesCache != NULL));
  1223. if (SessionData->CacheDirectoryChanges &&
  1224. FDirectoryChangesCache->GetDirectoryChange(PeekCurrentDirectory(),
  1225. Directory, CachedDirectory))
  1226. {
  1227. LogEvent(FORMAT("Cached directory change via \"%s\" to \"%s\".",
  1228. (Directory, CachedDirectory)));
  1229. FFileSystem->CachedChangeDirectory(CachedDirectory);
  1230. }
  1231. else
  1232. {
  1233. LogEvent(FORMAT("Changing directory to \"%s\".", (Directory)));
  1234. FFileSystem->ChangeDirectory(Directory);
  1235. }
  1236. FLastDirectoryChange = Directory;
  1237. ReactOnCommand(fsChangeDirectory);
  1238. }
  1239. catch (Exception &E)
  1240. {
  1241. CommandError(&E, FMTLOAD(CHANGE_DIR_ERROR, (Directory)));
  1242. }
  1243. }
  1244. //---------------------------------------------------------------------------
  1245. void __fastcall TTerminal::LookupUserGroups()
  1246. {
  1247. assert(FFileSystem);
  1248. assert(IsCapable[fcUserGroupListing]);
  1249. try
  1250. {
  1251. FUserGroupsLookedup = true;
  1252. LogEvent("Looking up current user groups.");
  1253. FFileSystem->LookupUserGroups();
  1254. ReactOnCommand(fsLookupUserGroups);
  1255. if (IsLogging())
  1256. {
  1257. LogEvent("Following groups found:");
  1258. for (int Index = 0; Index < FUserGroups->Count; Index++)
  1259. {
  1260. LogEvent(AnsiString(" ") + FUserGroups->Strings[Index]);
  1261. }
  1262. }
  1263. }
  1264. catch (Exception &E)
  1265. {
  1266. CommandError(&E, LoadStr(LOOKUP_GROUPS_ERROR));
  1267. }
  1268. }
  1269. //---------------------------------------------------------------------------
  1270. void __fastcall TTerminal::AnyCommand(const AnsiString Command)
  1271. {
  1272. assert(FFileSystem);
  1273. try
  1274. {
  1275. DirectoryModified(CurrentDirectory, false);
  1276. LogEvent("Executing used defined command.");
  1277. FFileSystem->AnyCommand(Command);
  1278. ReactOnCommand(fsAnyCommand);
  1279. }
  1280. catch (Exception &E)
  1281. {
  1282. if (ExceptionOnFail || (E.InheritsFrom(__classid(EFatal)))) throw;
  1283. else ShowExtendedException(&E, this);
  1284. }
  1285. }
  1286. //---------------------------------------------------------------------------
  1287. bool __fastcall TTerminal::CreateLocalFile(const AnsiString FileName,
  1288. TFileOperationProgressType * OperationProgress, HANDLE * AHandle)
  1289. {
  1290. assert(AHandle);
  1291. bool Result = true;
  1292. FILE_OPERATION_LOOP (FMTLOAD(CREATE_FILE_ERROR, (FileName)),
  1293. bool Done;
  1294. do
  1295. {
  1296. *AHandle = CreateFile(FileName.c_str(), GENERIC_WRITE, 0, NULL,
  1297. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  1298. Done = (*AHandle != INVALID_HANDLE_VALUE);
  1299. if (!Done)
  1300. {
  1301. int FileAttr;
  1302. if (FileExists(FileName) &&
  1303. (((FileAttr = FileGetAttr(FileName)) & faReadOnly) != 0))
  1304. {
  1305. if (OperationProgress->NoToAll)
  1306. {
  1307. Result = false;
  1308. }
  1309. else if (!OperationProgress->YesToAll)
  1310. {
  1311. int Answer;
  1312. SUSPEND_OPERATION
  1313. (
  1314. Answer = DoQueryUser(
  1315. FMTLOAD(READ_ONLY_OVERWRITE, (FileName)),
  1316. qaYes | qaNo | qaAbort | qaYesToAll | qaNoToAll, 0);
  1317. );
  1318. switch (Answer) {
  1319. case qaYesToAll: OperationProgress->YesToAll = true; break;
  1320. case qaAbort: OperationProgress->Cancel = csCancel; // continue on next case
  1321. case qaNoToAll: OperationProgress->NoToAll = true;
  1322. case qaNo: Result = false; break;
  1323. }
  1324. }
  1325. if (Result)
  1326. {
  1327. FILE_OPERATION_LOOP (FMTLOAD(CANT_SET_ATTRS, (FileName)),
  1328. if (FileSetAttr(FileName, FileAttr & ~faReadOnly) != 0)
  1329. {
  1330. EXCEPTION;
  1331. }
  1332. );
  1333. }
  1334. else
  1335. {
  1336. Done = true;
  1337. }
  1338. }
  1339. else
  1340. {
  1341. EXCEPTION;
  1342. }
  1343. }
  1344. }
  1345. while (!Done);
  1346. );
  1347. return Result;
  1348. }
  1349. //---------------------------------------------------------------------------
  1350. void __fastcall TTerminal::OpenLocalFile(const AnsiString FileName,
  1351. int Access, int * AAttrs, HANDLE * AHandle, unsigned long * ACTime,
  1352. unsigned long * AMTime, unsigned long * AATime, __int64 * ASize,
  1353. bool TryWriteReadOnly)
  1354. {
  1355. int Attrs = 0;
  1356. HANDLE Handle = 0;
  1357. FILE_OPERATION_LOOP (FMTLOAD(FILE_NOT_EXISTS, (FileName)),
  1358. Attrs = FileGetAttr(FileName);
  1359. if (Attrs == -1) EXCEPTION;
  1360. )
  1361. if ((Attrs & faDirectory) == 0)
  1362. {
  1363. bool NoHandle = false;
  1364. if (!TryWriteReadOnly && (Access == GENERIC_WRITE) &&
  1365. ((Attrs & faReadOnly) != 0))
  1366. {
  1367. Access = GENERIC_READ;
  1368. NoHandle = true;
  1369. }
  1370. FILE_OPERATION_LOOP (FMTLOAD(OPENFILE_ERROR, (FileName)),
  1371. Handle = CreateFile(FileName.c_str(), Access,
  1372. Access == GENERIC_READ ? FILE_SHARE_READ : 0,
  1373. NULL, OPEN_EXISTING, 0, 0);
  1374. if (Handle == INVALID_HANDLE_VALUE)
  1375. {
  1376. Handle = 0;
  1377. EXCEPTION;
  1378. }
  1379. );
  1380. try
  1381. {
  1382. if (AATime || AMTime)
  1383. {
  1384. // Get last file access and modification time
  1385. FILE_OPERATION_LOOP (FMTLOAD(CANT_GET_ATTRS, (FileName)),
  1386. FILETIME ATime;
  1387. FILETIME MTime;
  1388. FILETIME CTime;
  1389. if (!GetFileTime(Handle, &CTime, &ATime, &MTime)) EXCEPTION;
  1390. if (ACTime) TIME_WIN_TO_POSIX(CTime, *ACTime);
  1391. if (AATime) TIME_WIN_TO_POSIX(ATime, *AATime);
  1392. if (AMTime) TIME_WIN_TO_POSIX(MTime, *AMTime);
  1393. );
  1394. }
  1395. if (ASize)
  1396. {
  1397. // Get file size
  1398. FILE_OPERATION_LOOP (FMTLOAD(CANT_GET_ATTRS, (FileName)),
  1399. unsigned long LSize;
  1400. unsigned long HSize;
  1401. LSize = GetFileSize(Handle, &HSize);
  1402. if ((LSize == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) EXCEPTION;
  1403. *ASize = (__int64(HSize) << 32) + LSize;
  1404. );
  1405. }
  1406. if ((AHandle == NULL) || NoHandle)
  1407. {
  1408. CloseHandle(Handle);
  1409. Handle = NULL;
  1410. }
  1411. }
  1412. catch(...)
  1413. {
  1414. CloseHandle(Handle);
  1415. throw;
  1416. }
  1417. }
  1418. if (AAttrs) *AAttrs = Attrs;
  1419. if (AHandle) *AHandle = Handle;
  1420. }
  1421. //---------------------------------------------------------------------------
  1422. void __fastcall TTerminal::CalculateLocalFileSize(const AnsiString FileName,
  1423. const TSearchRec Rec, /*__int64*/ void * Size)
  1424. {
  1425. if ((Rec.Attr & faDirectory) == 0)
  1426. {
  1427. (*static_cast<__int64*>(Size)) +=
  1428. (static_cast<__int64>(Rec.FindData.nFileSizeHigh) << 32) +
  1429. Rec.FindData.nFileSizeLow;
  1430. }
  1431. if (OperationProgress && OperationProgress->Operation == foCalculateSize)
  1432. {
  1433. if (OperationProgress->Cancel != csContinue) Abort();
  1434. OperationProgress->SetFile(FileName);
  1435. }
  1436. }
  1437. //---------------------------------------------------------------------------
  1438. void __fastcall TTerminal::CalculateLocalFilesSize(TStrings * FileList, __int64 & Size)
  1439. {
  1440. Size = 0;
  1441. TFileOperationProgressType OperationProgress(FOnProgress, FOnFinished);
  1442. OperationProgress.Start(foCalculateSize, osLocal, FileList->Count);
  1443. try
  1444. {
  1445. assert(!FOperationProgress);
  1446. FOperationProgress = &OperationProgress;
  1447. TSearchRec Rec;
  1448. for (int Index = 0; Index < FileList->Count; Index++)
  1449. {
  1450. if (FileSearchRec(FileList->Strings[Index], Rec))
  1451. {
  1452. if (Rec.Attr & faDirectory)
  1453. {
  1454. ProcessLocalDirectory(FileList->Strings[Index],
  1455. CalculateLocalFileSize, &Size);
  1456. }
  1457. CalculateLocalFileSize(FileList->Strings[Index], Rec, &Size);
  1458. }
  1459. }
  1460. }
  1461. __finally
  1462. {
  1463. FOperationProgress = NULL;
  1464. OperationProgress.Stop();
  1465. }
  1466. }
  1467. //---------------------------------------------------------------------------
  1468. struct TSynchronizeFileData
  1469. {
  1470. int Time;
  1471. int Attr;
  1472. unsigned long SizeHigh;
  1473. unsigned long SizeLow;
  1474. FILETIME LastWriteTime;
  1475. bool Modified;
  1476. bool New;
  1477. };
  1478. //---------------------------------------------------------------------------
  1479. struct TSynchronizeData
  1480. {
  1481. AnsiString LocalDirectory;
  1482. AnsiString RemoteDirectory;
  1483. TTerminal::TSynchronizeMode Mode;
  1484. int Params;
  1485. TSynchronizeDirectory OnSynchronizeDirectory;
  1486. TStringList * LocalFileList;
  1487. TStringList * ModifiedRemoteFileList;
  1488. TStringList * NewRemoteFileList;
  1489. };
  1490. //---------------------------------------------------------------------------
  1491. void __fastcall TTerminal::Synchronize(const AnsiString LocalDirectory,
  1492. const AnsiString RemoteDirectory, TSynchronizeMode Mode, int Params,
  1493. TSynchronizeDirectory OnSynchronizeDirectory)
  1494. {
  1495. BeginTransaction();
  1496. try
  1497. {
  1498. DoSynchronizeDirectory(LocalDirectory, RemoteDirectory, Mode, Params,
  1499. OnSynchronizeDirectory);
  1500. }
  1501. __finally
  1502. {
  1503. EndTransaction();
  1504. }
  1505. }
  1506. //---------------------------------------------------------------------------
  1507. void __fastcall TTerminal::DoSynchronizeDirectory(const AnsiString LocalDirectory,
  1508. const AnsiString RemoteDirectory, TSynchronizeMode Mode, int Params,
  1509. TSynchronizeDirectory OnSynchronizeDirectory)
  1510. {
  1511. TSearchRec SearchRec;
  1512. bool Found;
  1513. bool Delete = (Params & spDelete) != 0;
  1514. TSynchronizeData Data;
  1515. Data.LocalDirectory = IncludeTrailingBackslash(LocalDirectory);
  1516. Data.RemoteDirectory = UnixIncludeTrailingBackslash(RemoteDirectory);
  1517. Data.Mode = Mode;
  1518. Data.Params = Params;
  1519. Data.OnSynchronizeDirectory = OnSynchronizeDirectory;
  1520. Data.LocalFileList = NULL;
  1521. Data.NewRemoteFileList = NULL;
  1522. Data.ModifiedRemoteFileList = NULL;
  1523. TStrings * LocalFileList = NULL;
  1524. LogEvent(FORMAT("Synchronizing local directory '%s' with remote directory '%s', "
  1525. "mode = %d, params = %d", (LocalDirectory, RemoteDirectory,
  1526. int(Mode), int(Params))));
  1527. bool Continue = true;
  1528. OnSynchronizeDirectory(LocalDirectory, RemoteDirectory, Continue);
  1529. if (!Continue)
  1530. {
  1531. Abort();
  1532. }
  1533. try
  1534. {
  1535. Data.LocalFileList = new TStringList();
  1536. Data.LocalFileList->Sorted = true;
  1537. Data.LocalFileList->CaseSensitive = false;
  1538. Data.NewRemoteFileList = new TStringList();
  1539. Data.ModifiedRemoteFileList = new TStringList();
  1540. LocalFileList = new TStringList();
  1541. FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (LocalDirectory)),
  1542. int FindAttrs = faReadOnly | faHidden | faSysFile | faDirectory | faArchive;
  1543. Found = (FindFirst(Data.LocalDirectory + "*.*", FindAttrs, SearchRec) == 0);
  1544. );
  1545. if (Found)
  1546. {
  1547. try
  1548. {
  1549. AnsiString FileName;
  1550. while (Found)
  1551. {
  1552. FileName = SearchRec.Name;
  1553. if ((FileName != ".") && (FileName != ".."))
  1554. {
  1555. TSynchronizeFileData * FileData = new TSynchronizeFileData;
  1556. FileData->Time = SearchRec.Time;
  1557. FileData->SizeHigh = SearchRec.FindData.nFileSizeHigh;
  1558. FileData->SizeLow = SearchRec.FindData.nFileSizeLow;
  1559. FileData->Attr = SearchRec.Attr;
  1560. FileData->LastWriteTime = SearchRec.FindData.ftLastWriteTime;
  1561. FileData->New = true;
  1562. FileData->Modified = false;
  1563. Data.LocalFileList->AddObject(FileName,
  1564. reinterpret_cast<TObject*>(FileData));
  1565. }
  1566. FILE_OPERATION_LOOP (FMTLOAD(LIST_DIR_ERROR, (LocalDirectory)),
  1567. Found = (FindNext(SearchRec) == 0);
  1568. );
  1569. }
  1570. }
  1571. __finally
  1572. {
  1573. FindClose(SearchRec);
  1574. }
  1575. ProcessDirectory(RemoteDirectory, SynchronizeFile, &Data);
  1576. TSynchronizeFileData * FileData;
  1577. for (int Index = 0; Index < Data.LocalFileList->Count; Index++)
  1578. {
  1579. FileData = reinterpret_cast<TSynchronizeFileData *>
  1580. (Data.LocalFileList->Objects[Index]);
  1581. if ((FileData->Modified && ((Mode == smBoth) || (Mode == smRemote))) ||
  1582. (FileData->New))
  1583. {
  1584. LocalFileList->Add(Data.LocalDirectory + Data.LocalFileList->Strings[Index]);
  1585. }
  1586. }
  1587. TCopyParamType CopyParam = Configuration->CopyParam;
  1588. CopyParam.PreserveTime = true;
  1589. int CopyParams = (Params & spNoConfirmation) != 0 ? cpNoConfirmation : 0;
  1590. if (LocalFileList->Count > 0)
  1591. {
  1592. bool Result;
  1593. if ((Mode == smBoth) || (Mode == smRemote))
  1594. {
  1595. Result = CopyToRemote(LocalFileList, RemoteDirectory, &CopyParam, CopyParams);
  1596. }
  1597. else if ((Mode == smLocal) && Delete)
  1598. {
  1599. Result = DeleteLocalFiles(LocalFileList);
  1600. }
  1601. if (!Result)
  1602. {
  1603. Abort();
  1604. }
  1605. }
  1606. if ((Mode == smBoth) || (Mode == smLocal))
  1607. {
  1608. Data.ModifiedRemoteFileList->AddStrings(Data.NewRemoteFileList);
  1609. if (Data.ModifiedRemoteFileList->Count > 0)
  1610. {
  1611. if (!CopyToLocal(Data.ModifiedRemoteFileList, LocalDirectory,
  1612. &CopyParam, CopyParams))
  1613. {
  1614. Abort();
  1615. }
  1616. }
  1617. }
  1618. if ((Mode == smRemote) && Delete && (Data.NewRemoteFileList->Count > 0))
  1619. {
  1620. if (!DeleteFiles(Data.NewRemoteFileList))
  1621. {
  1622. Abort();
  1623. }
  1624. }
  1625. }
  1626. }
  1627. __finally
  1628. {
  1629. if (Data.LocalFileList != NULL)
  1630. {
  1631. for (int Index = 0; Index < Data.LocalFileList->Count; Index++)
  1632. {
  1633. delete reinterpret_cast<TSynchronizeFileData*>
  1634. (Data.LocalFileList->Objects[Index]);
  1635. }
  1636. delete Data.LocalFileList;
  1637. }
  1638. TStringList * FileList = Data.NewRemoteFileList;
  1639. while (FileList != Data.ModifiedRemoteFileList)
  1640. {
  1641. if (FileList != NULL)
  1642. {
  1643. for (int Index = 0; Index < FileList->Count; Index++)
  1644. {
  1645. delete static_cast<TRemoteFile*>(FileList->Objects[Index]);
  1646. }
  1647. delete FileList;
  1648. }
  1649. FileList = Data.ModifiedRemoteFileList;
  1650. }
  1651. delete LocalFileList;
  1652. }
  1653. }
  1654. //---------------------------------------------------------------------------
  1655. void __fastcall TTerminal::SynchronizeFile(const AnsiString FileName,
  1656. const TRemoteFile * File, /*TSynchronizeData*/ void * Param)
  1657. {
  1658. TSynchronizeData * Data = static_cast<TSynchronizeData *>(Param);
  1659. bool Modified = false;
  1660. int Index = Data->LocalFileList->IndexOf(File->FileName);
  1661. bool New = (Index < 0);
  1662. if (!New)
  1663. {
  1664. TSynchronizeFileData * LocalData =
  1665. reinterpret_cast<TSynchronizeFileData *>(Data->LocalFileList->Objects[Index]);
  1666. LocalData->New = false;
  1667. bool LocalDirectory = (LocalData->Attr & faDirectory) != 0;
  1668. if (File->IsDirectory != LocalDirectory)
  1669. {
  1670. LogEvent(FORMAT("%s is directory on one side, but file on the another",
  1671. (File->FileName)));
  1672. }
  1673. else if (!File->IsDirectory)
  1674. {
  1675. FILETIME LocalLastWriteTime;
  1676. SYSTEMTIME SystemLastWriteTime;
  1677. FileTimeToLocalFileTime(&LocalData->LastWriteTime, &LocalLastWriteTime);
  1678. FileTimeToSystemTime(&LocalLastWriteTime, &SystemLastWriteTime);
  1679. TDateTime LocalTime = SystemTimeToDateTime(SystemLastWriteTime);
  1680. TDateTime RemoteTime = File->Modification;
  1681. UnifyDateTimePrecision(LocalTime, RemoteTime);
  1682. if (LocalTime < RemoteTime)
  1683. {
  1684. Modified = true;
  1685. }
  1686. else if (LocalTime > RemoteTime)
  1687. {
  1688. LocalData->Modified = true;
  1689. }
  1690. }
  1691. else
  1692. {
  1693. DoSynchronizeDirectory(
  1694. Data->LocalDirectory + File->FileName,
  1695. Data->RemoteDirectory + File->FileName,
  1696. Data->Mode, Data->Params, Data->OnSynchronizeDirectory);
  1697. }
  1698. }
  1699. if (New || Modified)
  1700. {
  1701. assert(!New || !Modified);
  1702. TStringList * FileList = New ? Data->NewRemoteFileList :
  1703. Data->ModifiedRemoteFileList;
  1704. FileList->AddObject(FileName,
  1705. const_cast<TRemoteFile *>(File)->Duplicate());
  1706. }
  1707. }
  1708. //---------------------------------------------------------------------------
  1709. bool __fastcall TTerminal::CopyToRemote(TStrings * FilesToCopy,
  1710. const AnsiString TargetDir, const TCopyParamType * CopyParam, int Params)
  1711. {
  1712. assert(FFileSystem);
  1713. assert(FilesToCopy);
  1714. bool Result = false;
  1715. bool DisconnectWhenComplete = false;
  1716. try
  1717. {
  1718. __int64 Size;
  1719. if (CopyParam->CalculateSize)
  1720. {
  1721. CalculateLocalFilesSize(FilesToCopy, Size);
  1722. }
  1723. TFileOperationProgressType OperationProgress(FOnProgress, FOnFinished);
  1724. OperationProgress.Start((Params & cpDelete ? foMove : foCopy), osLocal,
  1725. FilesToCopy->Count, Params & cpDragDrop, TargetDir);
  1726. if (CopyParam->CalculateSize)
  1727. {
  1728. OperationProgress.SetTotalSize(Size);
  1729. }
  1730. FOperationProgress = &OperationProgress;
  1731. try
  1732. {
  1733. AnsiString UnlockedTargetDir = TranslateLockedPath(TargetDir, false);
  1734. BeginTransaction();
  1735. try
  1736. {
  1737. if (IsLogging())
  1738. {
  1739. LogEvent(FORMAT("Copying %d files/directories to remote directory "
  1740. "\"%s\"", (FilesToCopy->Count, TargetDir)));
  1741. LogEvent(CopyParam->LogStr);
  1742. }
  1743. FFileSystem->CopyToRemote(FilesToCopy, UnlockedTargetDir,
  1744. CopyParam, Params, &OperationProgress, DisconnectWhenComplete);
  1745. }
  1746. __finally
  1747. {
  1748. if (Active)
  1749. {
  1750. ReactOnCommand(fsCopyToRemote);
  1751. EndTransaction();
  1752. }
  1753. }
  1754. if (OperationProgress.Cancel == csContinue)
  1755. {
  1756. Result = true;
  1757. }
  1758. }
  1759. __finally
  1760. {
  1761. OperationProgress.Stop();
  1762. FOperationProgress = NULL;
  1763. }
  1764. }
  1765. catch (Exception &E)
  1766. {
  1767. CommandError(&E, LoadStr(TOREMOTE_COPY_ERROR));
  1768. DisconnectWhenComplete = false;
  1769. }
  1770. if (DisconnectWhenComplete) CloseOnCompletion();
  1771. return Result;
  1772. }
  1773. //---------------------------------------------------------------------------
  1774. bool __fastcall TTerminal::CopyToLocal(TStrings * FilesToCopy,
  1775. const AnsiString TargetDir, const TCopyParamType * CopyParam, int Params)
  1776. {
  1777. assert(FFileSystem);
  1778. // see scp.c: sink(), tolocal()
  1779. bool Result = false;
  1780. bool OwnsFileList = (FilesToCopy == NULL);
  1781. bool DisconnectWhenComplete = false;
  1782. try
  1783. {
  1784. if (OwnsFileList)
  1785. {
  1786. FilesToCopy = new TStringList();
  1787. FilesToCopy->Assign(Files->SelectedFiles);
  1788. }
  1789. BeginTransaction();
  1790. try
  1791. {
  1792. __int64 TotalSize;
  1793. bool TotalSizeKnown = false;
  1794. TFileOperationProgressType OperationProgress(FOnProgress, FOnFinished);
  1795. if (CopyParam->CalculateSize)
  1796. {
  1797. ExceptionOnFail = true;
  1798. try
  1799. {
  1800. CalculateFilesSize(FilesToCopy, TotalSize, csIgnoreErrors);
  1801. TotalSizeKnown = true;
  1802. }
  1803. __finally
  1804. {
  1805. ExceptionOnFail = false;
  1806. }
  1807. }
  1808. OperationProgress.Start((Params & cpDelete ? foMove : foCopy), osRemote,
  1809. FilesToCopy->Count, Params & cpDragDrop, TargetDir);
  1810. if (TotalSizeKnown)
  1811. {
  1812. OperationProgress.SetTotalSize(TotalSize);
  1813. }
  1814. FOperationProgress = &OperationProgress;
  1815. try
  1816. {
  1817. try
  1818. {
  1819. try
  1820. {
  1821. FFileSystem->CopyToLocal(FilesToCopy, TargetDir, CopyParam, Params,
  1822. &OperationProgress, DisconnectWhenComplete);
  1823. }
  1824. __finally
  1825. {
  1826. if (Active)
  1827. {
  1828. ReactOnCommand(fsCopyToLocal);
  1829. }
  1830. }
  1831. }
  1832. catch (Exception &E)
  1833. {
  1834. CommandError(&E, LoadStr(TOLOCAL_COPY_ERROR));
  1835. DisconnectWhenComplete = false;
  1836. }
  1837. if (OperationProgress.Cancel == csContinue)
  1838. {
  1839. Result = true;
  1840. }
  1841. }
  1842. __finally
  1843. {
  1844. FOperationProgress = NULL;
  1845. OperationProgress.Stop();
  1846. }
  1847. }
  1848. __finally
  1849. {
  1850. // If session is still active (no fatal error) we reload directory
  1851. // by calling EndTransaction
  1852. EndTransaction();
  1853. }
  1854. }
  1855. __finally
  1856. {
  1857. if (OwnsFileList) delete FilesToCopy;
  1858. }
  1859. if (DisconnectWhenComplete) CloseOnCompletion();
  1860. return Result;
  1861. }
  1862. //---------------------------------------------------------------------------
  1863. __fastcall TTerminalList::TTerminalList(TConfiguration * AConfiguration) :
  1864. TObjectList()
  1865. {
  1866. assert(AConfiguration);
  1867. FConfiguration = AConfiguration;
  1868. }
  1869. //---------------------------------------------------------------------------
  1870. __fastcall TTerminalList::~TTerminalList()
  1871. {
  1872. assert(Count == 0);
  1873. }
  1874. //---------------------------------------------------------------------------
  1875. TTerminal * __fastcall TTerminalList::NewTerminal(TSessionData * Data)
  1876. {
  1877. TTerminal * Terminal = new TTerminal();
  1878. try
  1879. {
  1880. Terminal->Configuration = FConfiguration;
  1881. Terminal->SessionData = Data;
  1882. Add(Terminal);
  1883. }
  1884. catch(...)
  1885. {
  1886. delete Terminal;
  1887. throw;
  1888. }
  1889. return Terminal;
  1890. }
  1891. //---------------------------------------------------------------------------
  1892. void __fastcall TTerminalList::FreeTerminal(TTerminal * Terminal)
  1893. {
  1894. assert(IndexOf(Terminal) >= 0);
  1895. Remove(Terminal);
  1896. }
  1897. //---------------------------------------------------------------------------
  1898. void __fastcall TTerminalList::FreeAndNullTerminal(TTerminal * & Terminal)
  1899. {
  1900. TTerminal * T = Terminal;
  1901. Terminal = NULL;
  1902. FreeTerminal(T);
  1903. }
  1904. //---------------------------------------------------------------------------
  1905. TTerminal * __fastcall TTerminalList::GetTerminal(int Index)
  1906. {
  1907. return dynamic_cast<TTerminal *>(Items[Index]);
  1908. }
  1909. //---------------------------------------------------------------------------
  1910. void __fastcall TTerminalList::Idle()
  1911. {
  1912. TTerminal * Terminal;
  1913. for (int i = 0; i < Count; i++)
  1914. {
  1915. Terminal = Terminals[i];
  1916. if (Terminal->Status == sshReady)
  1917. {
  1918. Terminal->Idle();
  1919. }
  1920. }
  1921. }