UnicodeString TCopyParamType::GetLogStr() const { wchar_t CaseC[] = L"NULFS"; wchar_t ModeC[] = L"BAM"; wchar_t ResumeC[] = L"YSN"; // OpenArray (ARRAYOFCONST) supports only up to 19 arguments, so we had to split it return FORMAT( L" PrTime: %s%s; PrRO: %s; Rght: %s; PrR: %s (%s); FnCs: %c; RIC: %c; " L"Resume: %c (%d); CalcS: %s; Mask: %s\n", BooleanToEngStr(GetPreserveTime()).c_str(), UnicodeString(GetPreserveTime() && GetPreserveTimeDirs() ? L"+Dirs" : L"").c_str(), BooleanToEngStr(GetPreserveReadOnly()).c_str(), GetRights().GetText().c_str(), BooleanToEngStr(GetPreserveRights()).c_str(), BooleanToEngStr(GetIgnorePermErrors()).c_str(), CaseC[GetFileNameCase()], CharToHex(GetInvalidCharsReplacement()).c_str(), ResumeC[GetResumeSupport()], (int)GetResumeThreshold(), BooleanToEngStr(GetCalculateSize()).c_str(), GetFileMask().c_str()) + FORMAT( L" TM: %c; ClAr: %s; RemEOF: %s; RemBOM: %s; CPS: %u; NewerOnly: %s; InclM: %s; ResumeL: %d\n" L" AscM: %s\n", ModeC[GetTransferMode()], BooleanToEngStr(GetClearArchive()).c_str(), BooleanToEngStr(GetRemoveCtrlZ()).c_str(), BooleanToEngStr(GetRemoveBOM()).c_str(), int(GetCPSLimit()), BooleanToEngStr(GetNewerOnly()).c_str(), GetIncludeFileMask().GetMasks().c_str(), ((FTransferSkipList.get() != nullptr) ? FTransferSkipList->GetCount() : 0) + (!FTransferResumeFile.IsEmpty() ? 1 : 0), GetAsciiFileMask().GetMasks().c_str()); }
UnicodeString TSessionLog::LogSensitive(UnicodeString Str) { if (FConfiguration->GetLogSensitive() && !Str.IsEmpty()) { return Str; } return BooleanToEngStr(!Str.IsEmpty()); }
//--------------------------------------------------------------------------- void TSessionLog::DoAddStartupInfo(TSessionData * Data) { TGuard Guard(FCriticalSection); BeginUpdate(); auto cleanup = finally([&]() { DeleteUnnecessary(); EndUpdate(); }); { #define ADF(S, ...) DoAdd(llMessage, FORMAT(S, ##__VA_ARGS__), MAKE_CALLBACK(TSessionLog::DoAddToSelf, this)); if (Data == nullptr) { AddSeparator(); ADF(L"NetBox %s (OS %s)", FConfiguration->GetVersionStr().c_str(), FConfiguration->GetOSVersionStr().c_str()); std::auto_ptr<THierarchicalStorage> Storage(FConfiguration->CreateStorage(false)); assert(Storage.get()); ADF(L"Configuration: %s", Storage->GetSource().c_str()); if (0) { typedef BOOL (WINAPI * TGetUserNameEx)(EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize); HINSTANCE Secur32 = LoadLibrary(L"secur32.dll"); TGetUserNameEx GetUserNameEx = (Secur32 != nullptr) ? reinterpret_cast<TGetUserNameEx>(GetProcAddress(Secur32, "GetUserNameExW")) : nullptr; wchar_t UserName[UNLEN + 1]; unsigned long UserNameSize = LENOF(UserName); if ((GetUserNameEx == nullptr) || !GetUserNameEx(NameSamCompatible, (LPWSTR)UserName, &UserNameSize)) { wcscpy(UserName, L"<Failed to retrieve username>"); } ADF(L"Local account: %s", UserName); } unsigned short Y, M, D, H, N, S, MS; TDateTime DateTime = Now(); DateTime.DecodeDate(Y, M, D); DateTime.DecodeTime(H, N, S, MS); UnicodeString dt = FORMAT(L"%02d.%02d.%04d %02d:%02d:%02d", D, M, Y, H, N, S); // ADF(L"Login time: %s", FormatDateTime(L"dddddd tt", Now()).c_str()); ADF(L"Working directory: %s", GetCurrentDir().c_str()); // ADF(L"Command-line: %s", CmdLine.c_str()); // ADF(L"Time zone: %s", GetTimeZoneLogString().c_str()); ADF(L"Login time: %s", dt.c_str()); AddSeparator(); } else { if (0) { ADF(L"Session name: %s (%s)", Data->GetSessionName().c_str(), Data->GetSource().c_str()); } ADF(L"Host name: %s (Port: %d)", Data->GetHostNameExpanded().c_str(), Data->GetPortNumber()); if (0) { ADF(L"User name: %s (Password: %s, Key file: %s)", Data->GetUserNameExpanded().c_str(), BooleanToEngStr(!Data->GetPassword().IsEmpty()).c_str(), BooleanToEngStr(!Data->GetPublicKeyFile().IsEmpty()).c_str()) } ADF(L"Tunnel: %s", BooleanToEngStr(Data->GetTunnel()).c_str()); if (Data->GetTunnel()) { ADF(L"Tunnel: Host name: %s (Port: %d)", Data->GetTunnelHostName().c_str(), Data->GetTunnelPortNumber()); if (0) { ADF(L"Tunnel: User name: %s (Password: %s, Key file: %s)", Data->GetTunnelUserName().c_str(), BooleanToEngStr(!Data->GetTunnelPassword().IsEmpty()).c_str(), BooleanToEngStr(!Data->GetTunnelPublicKeyFile().IsEmpty()).c_str()); ADF(L"Tunnel: Local port number: %d", Data->GetTunnelLocalPortNumber()); } } ADF(L"Transfer Protocol: %s", Data->GetFSProtocolStr().c_str()); ADF(L"Code Page: %d", Data->GetCodePageAsNumber()); wchar_t * PingTypes = L"-NC"; TPingType PingType; intptr_t PingInterval; if (Data->GetFSProtocol() == fsFTP) { PingType = Data->GetFtpPingType(); PingInterval = Data->GetFtpPingInterval(); } else { PingType = Data->GetPingType(); PingInterval = Data->GetPingInterval(); } ADF(L"Ping type: %s, Ping interval: %d sec; Timeout: %d sec", UnicodeString(PingTypes[PingType]).c_str(), PingInterval, Data->GetTimeout()); ADF(L"Proxy: %s%s", ProxyMethodList[Data->GetProxyMethod()], Data->GetProxyMethod() == pmSystem ? ::Format(L" (%s)", ProxyMethodList[Data->GetActualProxyMethod()]).c_str() : L"") if (Data->GetProxyMethod() != ::pmNone) { ADF(L"HostName: %s (Port: %d); Username: %s; Passwd: %s", Data->GetProxyHost().c_str(), Data->GetProxyPort(), Data->GetProxyUsername().c_str(), BooleanToEngStr(!Data->GetProxyPassword().IsEmpty()).c_str()); if (Data->GetProxyMethod() == pmTelnet) { ADF(L"Telnet command: %s", Data->GetProxyTelnetCommand().c_str()); } if (Data->GetProxyMethod() == pmCmd) { ADF(L"Local command: %s", Data->GetProxyLocalCommand().c_str()); } } wchar_t const * BugFlags = L"+-A"; if (Data->GetUsesSsh()) { ADF(L"SSH protocol version: %s; Compression: %s", Data->GetSshProtStr().c_str(), BooleanToEngStr(Data->GetCompression()).c_str()); ADF(L"Bypass authentication: %s", BooleanToEngStr(Data->GetSshNoUserAuth()).c_str()); ADF(L"Try agent: %s; Agent forwarding: %s; TIS/CryptoCard: %s; KI: %s; GSSAPI: %s", BooleanToEngStr(Data->GetTryAgent()).c_str(), BooleanToEngStr(Data->GetAgentFwd()).c_str(), BooleanToEngStr(Data->GetAuthTIS()).c_str(), BooleanToEngStr(Data->GetAuthKI()).c_str(), BooleanToEngStr(Data->GetAuthGSSAPI()).c_str()); if (Data->GetAuthGSSAPI()) { ADF(L"GSSAPI: Forwarding: %s; Server realm: %s", BooleanToEngStr(Data->GetGSSAPIFwdTGT()).c_str(), Data->GetGSSAPIServerRealm().c_str()); } ADF(L"Ciphers: %s; Ssh2DES: %s", Data->GetCipherList().c_str(), BooleanToEngStr(Data->GetSsh2DES()).c_str()); UnicodeString Bugs; for (intptr_t Index = 0; Index < BUG_COUNT; ++Index) { Bugs += UnicodeString(BugFlags[Data->GetBug(static_cast<TSshBug>(Index))])+(Index<BUG_COUNT-1?L",":L""); } ADF(L"SSH Bugs: %s", Bugs.c_str()); ADF(L"Return code variable: %s; Lookup user groups: %c", Data->GetDetectReturnVar() ? UnicodeString(L"Autodetect").c_str() : Data->GetReturnVar().c_str(), BugFlags[Data->GetLookupUserGroups()]); ADF(L"Shell: %s", Data->GetShell().IsEmpty() ? UnicodeString(L"default").c_str() : Data->GetShell().c_str()); ADF(L"EOL: %d, UTF: %d", Data->GetEOLType(), Data->GetNotUtf()); ADF(L"Clear aliases: %s, Unset nat.vars: %s, Resolve symlinks: %s", BooleanToEngStr(Data->GetClearAliases()).c_str(), BooleanToEngStr(Data->GetUnsetNationalVars()).c_str(), BooleanToEngStr(Data->GetResolveSymlinks()).c_str()); ADF(L"LS: %s, Ign LS warn: %s, Scp1 Comp: %s", Data->GetListingCommand().c_str(), BooleanToEngStr(Data->GetIgnoreLsWarnings()).c_str(), BooleanToEngStr(Data->GetScp1Compatibility()).c_str()); } if (Data->GetFSProtocol() == fsSFTP) { UnicodeString Bugs; for (int Index = 0; Index < SFTP_BUG_COUNT; Index++) { Bugs += UnicodeString(BugFlags[Data->GetSFTPBug(static_cast<TSftpBug>(Index))])+(Index<SFTP_BUG_COUNT-1 ? L"," : L""); } ADF(L"SFTP Bugs: %s", Bugs.c_str()); ADF(L"SFTP Server: %s", Data->GetSftpServer().IsEmpty()? UnicodeString(L"default").c_str() : Data->GetSftpServer().c_str()); } if (Data->GetFSProtocol() == fsFTP) { UnicodeString Ftps; switch (Data->GetFtps()) { case ftpsImplicit: Ftps = L"Implicit TLS/SSL"; break; case ftpsExplicitSsl: Ftps = L"Explicit SSL"; break; case ftpsExplicitTls: Ftps = L"Explicit TLS"; break; default: assert(Data->GetFtps() == ftpsNone); Ftps = L"None"; break; } ADF(L"FTP: FTPS: %s; Passive: %s [Force IP: %c]; MLSD: %c [List all: %c]", Ftps.c_str(), BooleanToEngStr(Data->GetFtpPasvMode()).c_str(), BugFlags[Data->GetFtpForcePasvIp()], BugFlags[Data->GetFtpUseMlsd()], BugFlags[Data->GetFtpListAll()]); if (Data->GetFtps() != ftpsNone) { ADF(L"Session reuse: %s", BooleanToEngStr(Data->GetSslSessionReuse()).c_str()); ADF(L"TLS/SSL versions: %s-%s", GetTlsVersionName(Data->GetMinTlsVersion()).c_str(), GetTlsVersionName(Data->GetMaxTlsVersion()).c_str()); } } ADF(L"Local directory: %s, Remote directory: %s, Update: %s, Cache: %s", (Data->GetLocalDirectory().IsEmpty() ? UnicodeString(L"default").c_str() : Data->GetLocalDirectory().c_str()), (Data->GetRemoteDirectory().IsEmpty() ? UnicodeString(L"home").c_str() : Data->GetRemoteDirectory().c_str()), BooleanToEngStr(Data->GetUpdateDirectories()).c_str(), BooleanToEngStr(Data->GetCacheDirectories()).c_str()); ADF(L"Cache directory changes: %s, Permanent: %s", BooleanToEngStr(Data->GetCacheDirectoryChanges()).c_str(), BooleanToEngStr(Data->GetPreserveDirectoryChanges()).c_str()); intptr_t TimeDifferenceMin = TimeToMinutes(Data->GetTimeDifference()); ADF(L"DST mode: %d; Timezone offset: %dh %dm", static_cast<int>(Data->GetDSTMode()), (TimeDifferenceMin / MinsPerHour), (TimeDifferenceMin % MinsPerHour)); if (Data->GetFSProtocol() == fsWebDAV) { ADF(L"Compression: %s", BooleanToEngStr(Data->GetCompression()).c_str()); } AddSeparator(); } #undef ADF } }
void TSessionLog::DoAddStartupInfo(TSessionData *Data) { if (Data == nullptr) { AddSeparator(); UnicodeString OS = WindowsVersionLong(); AddToList(OS, WindowsProductName(), L" - "); ADF("NetBox %s (OS %s)", FConfiguration->GetProductVersionStr(), OS); { std::unique_ptr<THierarchicalStorage> Storage(FConfiguration->CreateConfigStorage()); DebugAssert(Storage.get()); ADF("Configuration: %s", Storage->GetSource()); } #if 0 typedef BOOL (WINAPI * TGetUserNameEx)(EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize); HINSTANCE Secur32 = LoadLibrary(L"secur32.dll"); TGetUserNameEx GetUserNameEx = (Secur32 != nullptr) ? reinterpret_cast<TGetUserNameEx>(::GetProcAddress(Secur32, "GetUserNameExW")) : nullptr; wchar_t UserName[UNLEN + 1]; ULONG UserNameSize = _countof(UserName); if ((GetUserNameEx == nullptr) || DebugAlwaysFalse(!GetUserNameEx(NameSamCompatible, (LPWSTR)UserName, &UserNameSize))) { wcscpy_s(UserName, UNLEN, L"<Failed to retrieve username>"); } #endif // #if 0 UnicodeString LogStr; if (FConfiguration->GetLogProtocol() <= 0) { LogStr = L"Normal"; } else if (FConfiguration->GetLogProtocol() == 1) { LogStr = L"Debug 1"; } else if (FConfiguration->GetLogProtocol() >= 2) { LogStr = L"Debug 2"; } #if 0 if (FConfiguration->GetLogSensitive()) { LogStr += L", Logging passwords"; } #endif // #if 0 if (FConfiguration->GetLogMaxSize() > 0) { LogStr += FORMAT(L", Rotating after: %s", SizeToStr(FConfiguration->GetLogMaxSize())); if (FConfiguration->GetLogMaxCount() > 0) { LogStr += FORMAT(L", Keeping at most %d logs", FConfiguration->GetLogMaxCount()); } } #if 0 ADF("Log level: %s", LogStr); ADF("Local account: %s", UserName); #endif // #if 0 ADF("Working directory: %s", GetCurrentDir()); ADF("Process ID: %d", intptr_t(GetCurrentProcessId())); #if 0 ADF("Command-line: %s", GetCmdLineLog()); if (FConfiguration->GetLogProtocol() >= 1) { AddOptions(GetGlobalOptions()); } #endif // #if 0 ADF("Time zone: %s", GetTimeZoneLogString()); if (!AdjustClockForDSTEnabled()) { ADF("Warning: System option \"Automatically adjust clock for Daylight Saving Time\" is disabled, timestamps will not be represented correctly"); } #if 0 ADF("Login time: %s", dt); #endif // #if 0 AddSeparator(); } else { #if 0 ADF("Session name: %s (%s)", Data->GetSessionName(), Data->GetSource()); ADF("Host name: %s (Port: %d)", Data->GetHostNameExpanded(), Data->GetPortNumber()); ADF("User name: %s (Password: %s, Key file: %s, Passphrase: %s)", Data->GetUserNameExpanded(), LogSensitive(Data->GetPassword()), LogSensitive(Data->GetPublicKeyFile()), LogSensitive(Data->GetPassphrase())) #endif // #if 0 if (Data->GetUsesSsh()) { ADF("Tunnel: %s", BooleanToEngStr(Data->GetTunnel())); if (Data->GetTunnel()) { ADF("Tunnel: Host name: %s (Port: %d)", Data->GetTunnelHostName(), Data->GetTunnelPortNumber()); #if 0 ADF("Tunnel: User name: %s (Password: %s, Key file: %s)", Data->GetTunnelUserName(), BooleanToEngStr(!Data->GetTunnelPassword().IsEmpty()), BooleanToEngStr(!Data->GetTunnelPublicKeyFile().IsEmpty())); ADF("Tunnel: Local port number: %d", Data->GetTunnelLocalPortNumber()); #endif // #if 0 } } ADF("Transfer Protocol: %s", Data->GetFSProtocolStr()); ADF("Code Page: %d", Data->GetCodePageAsNumber()); if (Data->GetUsesSsh() || (Data->GetFSProtocol() == fsFTP)) { TPingType PingType; intptr_t PingInterval; if (Data->GetFSProtocol() == fsFTP) { PingType = Data->GetFtpPingType(); PingInterval = Data->GetFtpPingInterval(); } else { PingType = Data->GetPingType(); PingInterval = Data->GetPingInterval(); } ADF("Ping type: %s, Ping interval: %d sec; Timeout: %d sec", EnumName(PingType, PingTypeNames), PingInterval, Data->GetTimeout()); ADF("Disable Nagle: %s", BooleanToEngStr(Data->GetTcpNoDelay())); } TProxyMethod ProxyMethod = Data->GetActualProxyMethod(); { UnicodeString fp = FORMAT(L"FTP proxy %d", Data->GetFtpProxyLogonType()); ADF("Proxy: %s", (Data->GetFtpProxyLogonType() != 0) ? fp : EnumName(ProxyMethod, ProxyMethodNames)); } if ((Data->GetFtpProxyLogonType() != 0) || (ProxyMethod != ::pmNone)) { ADF("ProxyHostName: %s (Port: %d); ProxyUsername: %s; Passwd: %s", Data->GetProxyHost(), Data->GetProxyPort(), Data->GetProxyUsername(), BooleanToEngStr(!Data->GetProxyPassword().IsEmpty())); if (ProxyMethod == pmTelnet) { ADF("Telnet command: %s", Data->GetProxyTelnetCommand()); } if (ProxyMethod == pmCmd) { ADF("Local command: %s", Data->GetProxyLocalCommand()); } } if (Data->GetUsesSsh() || (Data->GetFSProtocol() == fsFTP)) { ADF("Send buffer: %d", Data->GetSendBuf()); } if (Data->GetUsesSsh()) { ADF("SSH protocol version: %s; Compression: %s", Data->GetSshProtStr(), BooleanToEngStr(Data->GetCompression())); ADF("Bypass authentication: %s", BooleanToEngStr(Data->GetSshNoUserAuth())); ADF("Try agent: %s; Agent forwarding: %s; TIS/CryptoCard: %s; KI: %s; GSSAPI: %s", BooleanToEngStr(Data->GetTryAgent()), BooleanToEngStr(Data->GetAgentFwd()), BooleanToEngStr(Data->GetAuthTIS()), BooleanToEngStr(Data->GetAuthKI()), BooleanToEngStr(Data->GetAuthGSSAPI())); if (Data->GetAuthGSSAPI()) { ADF("GSSAPI: Forwarding: %s", BooleanToEngStr(Data->GetGSSAPIFwdTGT())); } ADF("Ciphers: %s; Ssh2DES: %s", Data->GetCipherList(), BooleanToEngStr(Data->GetSsh2DES())); ADF("KEX: %s", Data->GetKexList()); UnicodeString Bugs; for (intptr_t Index = 0; Index < BUG_COUNT; ++Index) { AddToList(Bugs, EnumName(Data->GetBug(static_cast<TSshBug>(Index)), AutoSwitchNames), L","); } ADF("SSH Bugs: %s", Bugs); ADF("Simple channel: %s", BooleanToEngStr(Data->GetSshSimple())); ADF("Return code variable: %s; Lookup user groups: %s", Data->GetDetectReturnVar() ? UnicodeString(L"Autodetect") : Data->GetReturnVar(), EnumName(Data->GetLookupUserGroups(), AutoSwitchNames)); ADF("Shell: %s", Data->GetShell().IsEmpty() ? UnicodeString(L"default") : Data->GetShell()); ADF("EOL: %s, UTF: %s", EnumName(Data->GetEOLType(), EOLTypeNames), EnumName(Data->GetNotUtf(), NotAutoSwitchNames)); // NotUtf duplicated in FTP branch ADF("Clear aliases: %s, Unset nat.vars: %s, Resolve symlinks: %s; Follow directory symlinks: %s", BooleanToEngStr(Data->GetClearAliases()), BooleanToEngStr(Data->GetUnsetNationalVars()), BooleanToEngStr(Data->GetResolveSymlinks()), BooleanToEngStr(Data->GetFollowDirectorySymlinks())); ADF("LS: %s, Ign LS warn: %s, Scp1 Comp: %s", Data->GetListingCommand(), BooleanToEngStr(Data->GetIgnoreLsWarnings()), BooleanToEngStr(Data->GetScp1Compatibility())); } if ((Data->GetFSProtocol() == fsSFTP) || (Data->GetFSProtocol() == fsSFTPonly)) { UnicodeString Bugs; for (intptr_t Index = 0; Index < SFTP_BUG_COUNT; ++Index) { AddToList(Bugs, EnumName(Data->GetSFTPBug(static_cast<TSftpBug>(Index)), AutoSwitchNames), L","); } ADF("SFTP Bugs: %s", Bugs); ADF("SFTP Server: %s", Data->GetSftpServer().IsEmpty() ? UnicodeString(L"default") : Data->GetSftpServer()); } bool FtpsOn = false; if (Data->GetFSProtocol() == fsFTP) { ADF("UTF: %s", EnumName(Data->GetNotUtf(), NotAutoSwitchNames)); // duplicated in UsesSsh branch UnicodeString Ftps; switch (Data->GetFtps()) { case ftpsImplicit: Ftps = L"Implicit TLS/SSL"; FtpsOn = true; break; case ftpsExplicitSsl: Ftps = L"Explicit SSL/TLS"; FtpsOn = true; break; case ftpsExplicitTls: Ftps = L"Explicit TLS/SSL"; FtpsOn = true; break; default: DebugAssert(Data->GetFtps() == ftpsNone); Ftps = L"None"; break; } // kind of hidden option, so do not reveal it unless it is set if (Data->GetFtpTransferActiveImmediately() != asAuto) { ADF("Transfer active immediately: %s", EnumName(Data->GetFtpTransferActiveImmediately(), AutoSwitchNames)); } ADF("FTPS: %s [Client certificate: %s]", Ftps, LogSensitive(Data->GetTlsCertificateFile())); ADF("FTP: Passive: %s [Force IP: %s]; MLSD: %s [List all: %s]; HOST: %s", BooleanToEngStr(Data->GetFtpPasvMode()), EnumName(Data->GetFtpForcePasvIp(), AutoSwitchNames), EnumName(Data->GetFtpUseMlsd(), AutoSwitchNames), EnumName(Data->GetFtpListAll(), AutoSwitchNames), EnumName(Data->GetFtpHost(), AutoSwitchNames)); } if (Data->GetFSProtocol() == fsWebDAV) { FtpsOn = (Data->GetFtps() != ftpsNone); ADF("HTTPS: %s [Client certificate: %s]", BooleanToEngStr(FtpsOn), LogSensitive(Data->GetTlsCertificateFile())); } if (FtpsOn) { if (Data->GetFSProtocol() == fsFTP) { ADF("Session reuse: %s", BooleanToEngStr(Data->GetSslSessionReuse())); } ADF("TLS/SSL versions: %s-%s", GetTlsVersionName(Data->GetMinTlsVersion()), GetTlsVersionName(Data->GetMaxTlsVersion())); } ADF("Local directory: %s, Remote directory: %s, Update: %s, Cache: %s", Data->GetLocalDirectory().IsEmpty() ? UnicodeString(L"default") : Data->GetLocalDirectory(), Data->GetRemoteDirectory().IsEmpty() ? UnicodeString(L"home") : Data->GetRemoteDirectory(), BooleanToEngStr(Data->GetUpdateDirectories()), BooleanToEngStr(Data->GetCacheDirectories())); ADF("Cache directory changes: %s, Permanent: %s", BooleanToEngStr(Data->GetCacheDirectoryChanges()), BooleanToEngStr(Data->GetPreserveDirectoryChanges())); ADF("Recycle bin: Delete to: %s, Overwritten to: %s, Bin path: %s", BooleanToEngStr(Data->GetDeleteToRecycleBin()), BooleanToEngStr(Data->GetOverwrittenToRecycleBin()), Data->GetRecycleBinPath()); if (Data->GetTrimVMSVersions()) { ADF("Trim VMS versions: %s", BooleanToEngStr(Data->GetTrimVMSVersions())); } UnicodeString TimeInfo; if ((Data->GetFSProtocol() == fsSFTP) || (Data->GetFSProtocol() == fsSFTPonly) || (Data->GetFSProtocol() == fsSCPonly) || (Data->GetFSProtocol() == fsWebDAV)) { AddToList(TimeInfo, FORMAT(L"DST mode: %s", EnumName(ToInt(Data->GetDSTMode()), DSTModeNames)), L";"); } if ((Data->GetFSProtocol() == fsSCPonly) || (Data->GetFSProtocol() == fsFTP)) { intptr_t TimeDifferenceMin = TimeToMinutes(Data->GetTimeDifference()); AddToList(TimeInfo, FORMAT(L"Timezone offset: %dh %dm", TimeDifferenceMin / MinsPerHour, TimeDifferenceMin % MinsPerHour), L";"); } ADSTR(TimeInfo); if (Data->GetFSProtocol() == fsWebDAV) { ADF("Compression: %s", BooleanToEngStr(Data->GetCompression())); } AddSeparator(); } }