SessionInfo.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <stdio.h>
  5. #include "Common.h"
  6. #include "SessionInfo.h"
  7. #include "Exceptions.h"
  8. #include "TextsCore.h"
  9. //---------------------------------------------------------------------------
  10. #pragma package(smart_init)
  11. //---------------------------------------------------------------------------
  12. TSessionInfo::TSessionInfo()
  13. {
  14. LoginTime = Now();
  15. }
  16. //---------------------------------------------------------------------------
  17. TFileSystemInfo::TFileSystemInfo()
  18. {
  19. memset(&IsCapable, false, sizeof(IsCapable));
  20. }
  21. //---------------------------------------------------------------------------
  22. const char *LogLineMarks = "<>!.*";
  23. __fastcall TSessionLog::TSessionLog(TSessionUI* UI, TSessionData * SessionData,
  24. TConfiguration * Configuration):
  25. TStringList()
  26. {
  27. FCriticalSection = new TCriticalSection;
  28. FConfiguration = Configuration;
  29. FParent = NULL;
  30. FUI = UI;
  31. FSessionData = SessionData;
  32. FFile = NULL;
  33. FLoggedLines = 0;
  34. FTopIndex = -1;
  35. FCurrentLogFileName = "";
  36. FCurrentFileName = "";
  37. ReflectSettings();
  38. }
  39. //---------------------------------------------------------------------------
  40. __fastcall TSessionLog::~TSessionLog()
  41. {
  42. CloseLogFile();
  43. delete FCriticalSection;
  44. }
  45. //---------------------------------------------------------------------------
  46. void __fastcall TSessionLog::Lock()
  47. {
  48. FCriticalSection->Enter();
  49. }
  50. //---------------------------------------------------------------------------
  51. void __fastcall TSessionLog::Unlock()
  52. {
  53. FCriticalSection->Leave();
  54. }
  55. //---------------------------------------------------------------------------
  56. AnsiString __fastcall TSessionLog::GetSessionName()
  57. {
  58. assert(FSessionData != NULL);
  59. return FSessionData->SessionName;
  60. }
  61. //---------------------------------------------------------------------------
  62. AnsiString __fastcall TSessionLog::GetLine(Integer Index)
  63. {
  64. return Strings[Index - FTopIndex];
  65. }
  66. //---------------------------------------------------------------------------
  67. TLogLineType __fastcall TSessionLog::GetType(int Index)
  68. {
  69. return (TLogLineType)Objects[Index - FTopIndex];
  70. }
  71. //---------------------------------------------------------------------------
  72. void __fastcall TSessionLog::DoAddToParent(TLogLineType Type, const AnsiString & Line)
  73. {
  74. assert(FParent != NULL);
  75. FParent->Add(Type, Line);
  76. }
  77. //---------------------------------------------------------------------------
  78. void __fastcall TSessionLog::DoAddToSelf(TLogLineType Type, const AnsiString & Line)
  79. {
  80. if (FTopIndex < 0)
  81. {
  82. FTopIndex = 0;
  83. }
  84. TStringList::AddObject(Line, (TObject*)Type);
  85. FLoggedLines++;
  86. if (LogToFile())
  87. {
  88. if (FFile == NULL)
  89. {
  90. OpenLogFile();
  91. }
  92. if (FFile != NULL)
  93. {
  94. AnsiString Timestamp = FormatDateTime(" yyyy-mm-dd hh:nn:ss.zzz ", Now());
  95. fputc(LogLineMarks[Type], (FILE *)FFile);
  96. fwrite(Timestamp.c_str(), Timestamp.Length(), 1, (FILE *)FFile);
  97. // use fwrite instead of fprintf to make sure that even
  98. // non-ascii data (unicode) gets in.
  99. fwrite(Line.c_str(), Line.Length(), 1, (FILE *)FFile);
  100. fputc('\n', (FILE *)FFile);
  101. }
  102. }
  103. }
  104. //---------------------------------------------------------------------------
  105. void __fastcall TSessionLog::DoAdd(TLogLineType Type, AnsiString Line,
  106. void __fastcall (__closure *f)(TLogLineType Type, const AnsiString & Line))
  107. {
  108. AnsiString Prefix;
  109. if (!Name.IsEmpty())
  110. {
  111. Prefix = "[" + Name + "] ";
  112. }
  113. while (!Line.IsEmpty())
  114. {
  115. f(Type, Prefix + CutToChar(Line, '\n', false));
  116. }
  117. }
  118. //---------------------------------------------------------------------------
  119. void __fastcall TSessionLog::Add(TLogLineType Type, const AnsiString & Line)
  120. {
  121. assert(FConfiguration);
  122. if (Logging)
  123. {
  124. try
  125. {
  126. if (FParent != NULL)
  127. {
  128. DoAdd(Type, Line, &DoAddToParent);
  129. }
  130. else
  131. {
  132. TGuard Guard(FCriticalSection);
  133. BeginUpdate();
  134. try
  135. {
  136. DoAdd(Type, Line, DoAddToSelf);
  137. }
  138. __finally
  139. {
  140. DeleteUnnecessary();
  141. EndUpdate();
  142. }
  143. }
  144. }
  145. catch (Exception &E)
  146. {
  147. // We failed logging, turn it of and notify user.
  148. FConfiguration->Logging = false;
  149. try
  150. {
  151. throw ExtException(&E, LOG_GEN_ERROR);
  152. }
  153. catch (Exception &E)
  154. {
  155. AddException(&E);
  156. FUI->ShowExtendedException(&E);
  157. }
  158. }
  159. }
  160. }
  161. //---------------------------------------------------------------------------
  162. void __fastcall TSessionLog::AddException(Exception * E)
  163. {
  164. if (E != NULL)
  165. {
  166. Add(llException, ExceptionLogString(E));
  167. }
  168. }
  169. //---------------------------------------------------------------------------
  170. void __fastcall TSessionLog::ReflectSettings()
  171. {
  172. TGuard Guard(FCriticalSection);
  173. FLogging = (FParent != NULL) || FConfiguration->Logging;
  174. // if logging to file was turned off or log file was change -> close current log file
  175. if ((FFile != NULL) &&
  176. (!LogToFile() || (FCurrentLogFileName != FConfiguration->LogFileName)))
  177. {
  178. CloseLogFile();
  179. }
  180. DeleteUnnecessary();
  181. }
  182. //---------------------------------------------------------------------------
  183. void __fastcall TSessionLog::SetParent(TSessionLog * value)
  184. {
  185. if (FParent != value)
  186. {
  187. FParent = value;
  188. ReflectSettings();
  189. }
  190. }
  191. //---------------------------------------------------------------------------
  192. bool __fastcall TSessionLog::LogToFile()
  193. {
  194. return Logging && FConfiguration->LogToFile && (FParent == NULL);
  195. }
  196. //---------------------------------------------------------------------------
  197. void __fastcall TSessionLog::CloseLogFile()
  198. {
  199. if (FFile != NULL)
  200. {
  201. fclose((FILE *)FFile);
  202. FFile = NULL;
  203. }
  204. FCurrentLogFileName = "";
  205. FCurrentFileName = "";
  206. }
  207. //---------------------------------------------------------------------------
  208. void TSessionLog::OpenLogFile()
  209. {
  210. try
  211. {
  212. assert(FFile == NULL);
  213. assert(FConfiguration != NULL);
  214. FCurrentLogFileName = FConfiguration->LogFileName;
  215. AnsiString NewFileName = StripPathQuotes(ExpandEnvironmentVariables(FCurrentLogFileName));
  216. TDateTime N = Now();
  217. for (int Index = 1; Index < NewFileName.Length(); Index++)
  218. {
  219. if (NewFileName[Index] == '&')
  220. {
  221. AnsiString Replacement;
  222. switch (tolower(NewFileName[Index + 1]))
  223. {
  224. case 'y':
  225. Replacement = FormatDateTime("yyyy", N);
  226. break;
  227. case 'm':
  228. Replacement = FormatDateTime("mm", N);
  229. break;
  230. case 'd':
  231. Replacement = FormatDateTime("dd", N);
  232. break;
  233. case 't':
  234. Replacement = FormatDateTime("hhnnss", N);
  235. break;
  236. case 'h':
  237. Replacement = MakeValidFileName(FSessionData->HostName);
  238. break;
  239. case 's':
  240. Replacement = MakeValidFileName(FSessionData->SessionName);
  241. break;
  242. case '&':
  243. Replacement = "&";
  244. break;
  245. default:
  246. Replacement = AnsiString("&") + NewFileName[Index + 1];
  247. break;
  248. }
  249. NewFileName.Delete(Index, 2);
  250. NewFileName.Insert(Replacement, Index);
  251. Index += Replacement.Length() - 1;
  252. }
  253. }
  254. FFile = fopen(NewFileName.c_str(), (FConfiguration->LogFileAppend ? "a" : "w"));
  255. if (FFile)
  256. {
  257. setvbuf((FILE *)FFile, NULL, _IONBF, BUFSIZ);
  258. FCurrentFileName = NewFileName;
  259. }
  260. else
  261. {
  262. throw Exception(FMTLOAD(LOG_OPENERROR, (NewFileName)));
  263. }
  264. }
  265. catch (Exception & E)
  266. {
  267. // We failed logging to file, turn it off and notify user.
  268. FCurrentLogFileName = "";
  269. FCurrentFileName = "";
  270. FConfiguration->LogToFile = false;
  271. try
  272. {
  273. throw ExtException(&E, LOG_GEN_ERROR);
  274. }
  275. catch (Exception & E)
  276. {
  277. AddException(&E);
  278. FUI->ShowExtendedException(&E);
  279. }
  280. }
  281. }
  282. //---------------------------------------------------------------------------
  283. void TSessionLog::DeleteUnnecessary()
  284. {
  285. BeginUpdate();
  286. try
  287. {
  288. if (!Logging || (FParent != NULL))
  289. {
  290. Clear();
  291. }
  292. else
  293. {
  294. while (!FConfiguration->LogWindowComplete && (Count > FConfiguration->LogWindowLines))
  295. {
  296. Delete(0);
  297. FTopIndex++;
  298. }
  299. }
  300. }
  301. __finally
  302. {
  303. EndUpdate();
  304. }
  305. }
  306. //---------------------------------------------------------------------------
  307. void __fastcall TSessionLog::AddStartupInfo()
  308. {
  309. if (Logging)
  310. {
  311. if (FParent != NULL)
  312. {
  313. // do not add session info for secondary session
  314. // (this should better be handled in the TSecondaryTerminal)
  315. }
  316. else
  317. {
  318. DoAddStartupInfo(FSessionData);
  319. }
  320. }
  321. }
  322. //---------------------------------------------------------------------------
  323. void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
  324. {
  325. assert(Logging);
  326. TGuard Guard(FCriticalSection);
  327. BeginUpdate();
  328. try
  329. {
  330. #define ADF(S, F) DoAdd(llMessage, FORMAT(S, F), DoAddToSelf);
  331. AddSeparator();
  332. ADF("WinSCP %s (OS %s)", (FConfiguration->VersionStr, FConfiguration->OSVersionStr));
  333. ADF("Login time: %s", (FormatDateTime("dddddd tt", Now())));
  334. AddSeparator();
  335. ADF("Session name: %s", (Data->SessionName));
  336. ADF("Host name: %s (Port: %d)", (Data->HostName, Data->PortNumber));
  337. ADF("User name: %s (Password: %s, Key file: %s)",
  338. (Data->UserName, BooleanToEngStr(!Data->Password.IsEmpty()),
  339. BooleanToEngStr(!Data->PublicKeyFile.IsEmpty())))
  340. ADF("Tunnel: %s", (BooleanToEngStr(Data->Tunnel)));
  341. if (Data->Tunnel)
  342. {
  343. ADF("Tunnel: Host name: %s (Port: %d)", (Data->TunnelHostName, Data->TunnelPortNumber));
  344. ADF("Tunnel: User name: %s (Password: %s, Key file: %s)",
  345. (Data->TunnelUserName, BooleanToEngStr(!Data->TunnelPassword.IsEmpty()),
  346. BooleanToEngStr(!Data->TunnelPublicKeyFile.IsEmpty())))
  347. ADF("Tunnel: Local port number: %d", (Data->TunnelLocalPortNumber));
  348. }
  349. ADF("Transfer Protocol: %s", (Data->FSProtocolStr));
  350. char * PingTypes = "-NC";
  351. TPingType PingType;
  352. int PingInterval;
  353. if (Data->FSProtocol == fsFTP)
  354. {
  355. PingType = Data->FtpPingType;
  356. PingInterval = Data->FtpPingInterval;
  357. }
  358. else
  359. {
  360. PingType = Data->PingType;
  361. PingInterval = Data->PingInterval;
  362. }
  363. ADF("Ping type: %s, Ping interval: %d sec; Timeout: %d sec",
  364. (AnsiString(PingTypes[PingType]), PingInterval, Data->Timeout));
  365. ADF("Proxy: %s", (ProxyMethodList[Data->ProxyMethod]));
  366. if (Data->ProxyMethod != pmNone)
  367. {
  368. ADF("HostName: %s (Port: %d); Username: %s; Passwd: %s",
  369. (Data->ProxyHost, Data->ProxyPort,
  370. Data->ProxyUsername, BooleanToEngStr(!Data->ProxyPassword.IsEmpty())));
  371. if (Data->ProxyMethod == pmTelnet)
  372. {
  373. ADF("Telnet command: %s", (Data->ProxyTelnetCommand));
  374. }
  375. }
  376. if (Data->UsesSsh)
  377. {
  378. ADF("SSH protocol version: %s; Compression: %s",
  379. (Data->SshProtStr, BooleanToEngStr(Data->Compression)));
  380. ADF("Agent forwarding: %s; TIS/CryptoCard: %s; KI: %s; GSSAPI: %s",
  381. (BooleanToEngStr(Data->AgentFwd), BooleanToEngStr(Data->AuthTIS),
  382. BooleanToEngStr(Data->AuthKI), BooleanToEngStr(Data->AuthGSSAPI)));
  383. if (Data->AuthGSSAPI)
  384. {
  385. ADF("GSSAPI: Forwarding: %s; Server realm: %s",
  386. (BooleanToEngStr(Data->GSSAPIFwdTGT), Data->GSSAPIServerRealm));
  387. }
  388. ADF("Ciphers: %s; Ssh2DES: %s",
  389. (Data->CipherList, BooleanToEngStr(Data->Ssh2DES)));
  390. AnsiString Bugs;
  391. char const * BugFlags = "A+-";
  392. for (int Index = 0; Index < BUG_COUNT; Index++)
  393. {
  394. Bugs += AnsiString(BugFlags[Data->Bug[(TSshBug)Index]])+(Index<BUG_COUNT-1?",":"");
  395. }
  396. ADF("SSH Bugs: %s", (Bugs));
  397. Bugs = "";
  398. for (int Index = 0; Index < SFTP_BUG_COUNT; Index++)
  399. {
  400. Bugs += AnsiString(BugFlags[Data->SFTPBug[(TSftpBug)Index]])+(Index<SFTP_BUG_COUNT-1?",":"");
  401. }
  402. ADF("SFTP Bugs: %s", (Bugs));
  403. ADF("Return code variable: %s; Lookup user groups: %s",
  404. ((Data->DetectReturnVar ? AnsiString("Autodetect") : Data->ReturnVar),
  405. BooleanToEngStr(Data->LookupUserGroups)));
  406. ADF("Shell: %s, EOL: %d", ((Data->Shell.IsEmpty()? AnsiString("default") : Data->Shell), Data->EOLType));
  407. ADF("Clear aliases: %s, Unset nat.vars: %s, Resolve symlinks: %s",
  408. (BooleanToEngStr(Data->ClearAliases), BooleanToEngStr(Data->UnsetNationalVars),
  409. BooleanToEngStr(Data->ResolveSymlinks)));
  410. ADF("Alias LS: %s, Ign LS warn: %s, Scp1 Comp: %s",
  411. (BooleanToEngStr(Data->AliasGroupList),
  412. BooleanToEngStr(Data->IgnoreLsWarnings),
  413. BooleanToEngStr(Data->Scp1Compatibility)));
  414. }
  415. if (Data->FSProtocol == fsFTP)
  416. {
  417. ADF("FTP: Passive: %s", (BooleanToEngStr(Data->FtpPasvMode)));
  418. }
  419. ADF("Local directory: %s, Remote directory: %s, Update: %s, Cache: %s",
  420. ((Data->LocalDirectory.IsEmpty() ? AnsiString("default") : Data->LocalDirectory),
  421. (Data->RemoteDirectory.IsEmpty() ? AnsiString("home") : Data->RemoteDirectory),
  422. BooleanToEngStr(Data->UpdateDirectories),
  423. BooleanToEngStr(Data->CacheDirectories)));
  424. ADF("Cache directory changes: %s, Permanent: %s",
  425. (BooleanToEngStr(Data->CacheDirectoryChanges),
  426. BooleanToEngStr(Data->PreserveDirectoryChanges)));
  427. ADF("DST mode: %d", (int(Data->DSTMode)));
  428. AddSeparator();
  429. #undef ADF
  430. }
  431. __finally
  432. {
  433. DeleteUnnecessary();
  434. EndUpdate();
  435. }
  436. }
  437. //---------------------------------------------------------------------------
  438. void __fastcall TSessionLog::AddSeparator()
  439. {
  440. Add(llMessage, "--------------------------------------------------------------------------");
  441. }
  442. //---------------------------------------------------------------------------
  443. int __fastcall TSessionLog::GetBottomIndex()
  444. {
  445. return (Count > 0 ? (TopIndex + Count - 1) : -1);
  446. }
  447. //---------------------------------------------------------------------------
  448. bool __fastcall TSessionLog::GetLoggingToFile()
  449. {
  450. assert((FFile == NULL) || LogToFile());
  451. return (FFile != NULL);
  452. }
  453. //---------------------------------------------------------------------------
  454. void __fastcall TSessionLog::Clear()
  455. {
  456. TGuard Guard(FCriticalSection);
  457. FTopIndex += Count;
  458. TStringList::Clear();
  459. }