mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
* Cast between closure types with a functional cast, not reinterpret_cast
A Borland __closure is a built-in (code, data) pair, so reinterpret_cast
between two closure types is allowed. Under standard C++ a closure is a
class, and reinterpret_cast cannot convert one class object into another.
The functional cast is the old C-style cast this line had before
"Refactoring old-style casts" (e5efed895), so C++Builder compiles it as it
did then, and a compiler implementing closures as classes can give it the
same meaning.
* Read the knocked FTP port's IPv4 address as 32 bits
The address is read through an unsigned long pointer. That is 32 bits on
Windows (LLP64), so it reads exactly the four address bytes there; on LP64
targets unsigned long is 64 bits, and the read runs four bytes past the
address into whatever follows it in gethostbyname's buffer. The assignment
to the 32-bit s_addr then keeps the right bytes on little-endian machines,
which is why it goes unnoticed, but the over-read is undefined. ULONG is 32
bits on every Windows compiler, as Windows API layers for POSIX define it
too.
* Compile the synchronize checklist's Explorer file operation on Windows only
TSynchronizeChecklistFileOperation carries out a synchronization checklist
through Explorer's IFileOperation (a Shell COM object), so that local
deletions go to the recycle bin with Explorer's progress and undo. Only
WinSCP's Windows GUI uses it (CustomScpExplorer.cpp). Elsewhere neither the
object nor the interfaces exist, and declaring them only to compile would
pretend to a facility that is not there; a frontend on another platform
implements the operation its own way. The class and its implementation are
guarded with _WIN32, which C++Builder defines, so the Windows build is
unchanged.
* Declare the SIOCATMARK result as ULONG, the type p_ioctlsocket takes
network.c declares ioctlsocket as taking ULONG * (its DECL_WINDOWS_FUNCTION)
but passes a u_long. Both are 32 bits on Windows, so the two agree there. On
an LP64 platform u_long is 64 bits and ULONG 32, so the pointer types differ
and the callee would write half the variable. ULONG is what the declaration
says, and is the same type on Windows.
* Pick aes-ni.c's _mm_setr_epi8 for any GCC-compatible compiler
MM_SETR_EPI8 uses _mm_setr_epi8 only under _WIN64, falling back to a brace
initialiser that is correct for MSVC's __m128i (a byte union) but fills
clang's and GCC's (a two-lane vector) wrongly; the _WIN64 condition fixed
that for Win64 builds only. Any compiler defining __GNUC__ (clang does) now
takes the intrinsic.
* Compile WinSCP's Windows-only additions to neon on Windows only
WinSCP builds neon for Win32 alone, and three of its additions assume it:
ne_openssl.c includes <windows.h> (it uses nothing from it), timed_connect
switches the socket to non-blocking mode with Winsock's ioctlsocket instead
of upstream's fcntl, and ne_sock_sspi_init calls into SSPI unconditionally.
On POSIX neon uses BSD sockets directly, so the include is guarded with
_WIN32, the two ioctlsocket branches are taken only on _WIN32 (upstream's
fcntl code beside them is used otherwise), and ne_sock_sspi_init calls SSPI
under HAVE_SSPI, as ne_sock_init's own call does, reporting failure (-1)
without it -- which WebDAVFileSystem.cpp already handles as SSPI being
unavailable. C++Builder defines _WIN32 and neon's Win32 config.h defines
HAVE_SSPI, so the Windows build is unchanged.
* Use in_addr's s_addr in FileZilla's proxy layer
AsyncProxySocketLayer.cpp reaches the IPv4 address through Winsock's union,
sin_addr.S_un.S_addr. Winsock also defines s_addr as exactly that member
(#define s_addr S_un.S_addr), and s_addr is the name BSD sockets and POSIX
give the field; a POSIX in_addr has no S_un. Same field, so the Windows
build is unchanged.
* Pass FileZilla's two tool strings as UnicodeString, not std::wstring
CFileZillaTools::GetClientString and CustomReason return std::wstring; the
rest of the interface between core and FileZilla, and both sides' own code,
use UnicodeString or wchar_t pointers. Built with a 2-byte wchar_t on a
platform whose C++ library assumes 4 (clang's -fshort-wchar on Linux),
std::wstring is unusable: libstdc++ provides basic_string<wchar_t> as a
precompiled extern template for its own wchar_t, and char_traits<wchar_t>
calls the C library's 4-byte wcslen and wmemcpy: a Linux build of
FtpFileSystem.cpp imported wcslen through it. The values are only built from
UnicodeString, compared with empty() and read with c_str(), so UnicodeString
is a direct replacement (IsEmpty for empty). On Windows, where wchar_t is 2
bytes throughout, behaviour is unchanged.
* Build storage key paths with backslashes on every platform
THierarchicalStorage joins registry and INI key paths (Sessions\My site)
through its IncludeTrailingBackslash and ExcludeTrailingBackslash members,
which defer to the RTL functions of those names. The RTL's add and strip the
platform's path delimiter: a backslash on Windows, a slash on POSIX, where
these functions also build local file paths. Keys are not file paths: their
separator is a backslash everywhere, and the INI file's sections say so. The
members now add and strip a backslash themselves; on Windows that is what
the RTL did, so the behaviour there is unchanged. Without this, on POSIX the
current key became "Sessions/", matched no section, and no stored site
loaded.
* Hand neon a copy of the TLS-init closure, not its two pointers
SetNeonTlsInit stores the closure in the neon session by reinterpreting it
as a TMethod and saving its code and data pointers, and ne_init_ssl_session
rebuilds it with MakeMethod. That relies on a closure being exactly those
two pointers, which only Borland's __closure is; with any other closure type
the saved words are its internals, read from a by-value parameter that is
gone by the time neon calls back, and the rebuilt closure is garbage (a
clang build's first WebDAV-over-TLS connection crashed there). The session
now holds a heap copy of the closure, freed by neon's destroy-session hook
-- which also covers the sessions libs3 creates and destroys itself -- and
ne_init_ssl_session calls that copy. On C++Builder the behaviour is the
same, at the cost of one small allocation per session.
* Take CString's search results as const wchar_t *
CString::Find, ReverseFind and FindOneOf search the const string c_str()
returns and keep the result in a wchar_t *. ISO C++ declares wcschr,
wcsrchr, wcsstr and wcspbrk on a const string as returning const wchar_t *,
as MSVC's and newer mingw-w64 headers (llvm-mingw's) do, so the
initialisation does not compile there. The pointers are only compared and
subtracted: const is all they need.
* Index the string a string-list property returns, not the property
GetLocales takes a character of Exts->Strings[Index]. Under clang the
__declspec(property) standing for TStrings::Strings' __property reads a
second subscript as the property's own second index, so the expression is a
two-argument call to the getter and does not compile (parentheses do not
change that). Read into a UnicodeString first, the second subscript indexes
the string the property returns, as under C++Builder.
---------
Co-authored-by: Eduardo Correia <ecorreia@apliant.com.br>
1427 lines
46 KiB
C++
1427 lines
46 KiB
C++
//---------------------------------------------------------------------------
|
|
#include <WinPCH.h>
|
|
#pragma hdrstop
|
|
|
|
#include "GUIConfiguration.h"
|
|
|
|
#include <FileInfo.h>
|
|
#include <Terminal.h>
|
|
#include <shlobj.h>
|
|
//---------------------------------------------------------------------------
|
|
const int ccLocal = ccUser;
|
|
const int ccShowResults = ccUser << 1;
|
|
const int ccCopyResults = ccUser << 2;
|
|
const int ccRemoteFiles = ccUser << 3;
|
|
const int ccShowResultsInMsgBox = ccUser << 4;
|
|
const int ccSet = 0x80000000;
|
|
const int SessionReopenAutoIdleDefault = 9000;
|
|
//---------------------------------------------------------------------------
|
|
static const unsigned int AdditionalLanguageMask = 0xFFFFFF00;
|
|
static const UnicodeString AdditionalLanguagePrefix(L"XX");
|
|
static const UnicodeString TranslationsSubFolder(L"Translations");
|
|
//---------------------------------------------------------------------------
|
|
TGUIConfiguration * GUIConfiguration = NULL;
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TGUICopyParamType::TGUICopyParamType()
|
|
: TCopyParamType()
|
|
{
|
|
GUIDefault();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TGUICopyParamType::TGUICopyParamType(const TCopyParamType & Source)
|
|
: TCopyParamType(Source)
|
|
{
|
|
GUIDefault();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TGUICopyParamType::TGUICopyParamType(const TGUICopyParamType & Source)
|
|
: TCopyParamType(Source)
|
|
{
|
|
GUIAssign(&Source);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUICopyParamType::Assign(const TCopyParamType * Source)
|
|
{
|
|
TCopyParamType::Assign(Source);
|
|
|
|
const TGUICopyParamType * GUISource;
|
|
GUISource = dynamic_cast<const TGUICopyParamType *>(Source);
|
|
if (GUISource != NULL)
|
|
{
|
|
GUIAssign(GUISource);
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUICopyParamType::GUIAssign(const TGUICopyParamType * Source)
|
|
{
|
|
Queue = Source->Queue;
|
|
QueueNoConfirmation = Source->QueueNoConfirmation;
|
|
QueueParallel = Source->QueueParallel;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUICopyParamType::Default()
|
|
{
|
|
TCopyParamType::Default();
|
|
|
|
GUIDefault();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUICopyParamType::GUIDefault()
|
|
{
|
|
Queue = false;
|
|
QueueNoConfirmation = true;
|
|
QueueParallel = true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUICopyParamType::Load(THierarchicalStorage * Storage)
|
|
{
|
|
TCopyParamType::Load(Storage);
|
|
|
|
Queue = Storage->ReadBool(L"Queue", Queue);
|
|
QueueNoConfirmation = Storage->ReadBool(L"QueueNoConfirmation", QueueNoConfirmation);
|
|
QueueParallel = Storage->ReadBool(L"QueueParallel", QueueParallel);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUICopyParamType::Save(THierarchicalStorage * Storage, const TCopyParamType * Defaults) const
|
|
{
|
|
DebugAssert(Defaults == NULL);
|
|
TCopyParamType::Save(Storage, Defaults);
|
|
|
|
Storage->WriteBool(L"Queue", Queue);
|
|
Storage->WriteBool(L"QueueNoConfirmation", QueueNoConfirmation);
|
|
Storage->WriteBool(L"QueueParallel", QueueParallel);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
TGUICopyParamType & __fastcall TGUICopyParamType::operator =(const TCopyParamType & rhp)
|
|
{
|
|
Assign(&rhp);
|
|
return *this;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
TGUICopyParamType & __fastcall TGUICopyParamType::operator =(const TGUICopyParamType & rhp)
|
|
{
|
|
Assign(&rhp);
|
|
return *this;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TCopyParamRuleData::Default()
|
|
{
|
|
HostName = L"";
|
|
UserName = L"";
|
|
RemoteDirectory = L"";
|
|
LocalDirectory = L"";
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TCopyParamRule::TCopyParamRule()
|
|
{
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TCopyParamRule::TCopyParamRule(const TCopyParamRuleData & Data)
|
|
{
|
|
FData = Data;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TCopyParamRule::TCopyParamRule(const TCopyParamRule & Source)
|
|
{
|
|
FData.HostName = Source.FData.HostName;
|
|
FData.UserName = Source.FData.UserName;
|
|
FData.RemoteDirectory = Source.FData.RemoteDirectory;
|
|
FData.LocalDirectory = Source.FData.LocalDirectory;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
#define C(Property) (Property == rhp.Property)
|
|
bool __fastcall TCopyParamRule::operator==(const TCopyParamRule & rhp) const
|
|
{
|
|
return
|
|
C(FData.HostName) &&
|
|
C(FData.UserName) &&
|
|
C(FData.RemoteDirectory) &&
|
|
C(FData.LocalDirectory) &&
|
|
true;
|
|
}
|
|
#undef C
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TCopyParamRule::Match(const UnicodeString & Mask,
|
|
const UnicodeString & Value, bool Path, bool Local, int ForceDirectoryMasks) const
|
|
{
|
|
bool Result;
|
|
if (Mask.IsEmpty())
|
|
{
|
|
Result = true;
|
|
}
|
|
else
|
|
{
|
|
TFileMasks M(ForceDirectoryMasks);
|
|
M.Masks = Mask;
|
|
if (Path)
|
|
{
|
|
Result = M.Matches(Value, Local, true);
|
|
}
|
|
else
|
|
{
|
|
Result = M.MatchesFileName(Value);
|
|
}
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TCopyParamRule::Matches(const TCopyParamRuleData & Value) const
|
|
{
|
|
return
|
|
Match(FData.HostName, Value.HostName, false, true, 0) &&
|
|
Match(FData.UserName, Value.UserName, false, true, 0) &&
|
|
Match(FData.RemoteDirectory, Value.RemoteDirectory, true, false, 1) &&
|
|
Match(FData.LocalDirectory, Value.LocalDirectory, true, true, 1);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TCopyParamRule::Load(THierarchicalStorage * Storage)
|
|
{
|
|
FData.HostName = Storage->ReadString(L"HostName", FData.HostName);
|
|
FData.UserName = Storage->ReadString(L"UserName", FData.UserName);
|
|
FData.RemoteDirectory = Storage->ReadString(L"RemoteDirectory", FData.RemoteDirectory);
|
|
FData.LocalDirectory = Storage->ReadString(L"LocalDirectory", FData.LocalDirectory);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TCopyParamRule::Save(THierarchicalStorage * Storage) const
|
|
{
|
|
Storage->WriteString(L"HostName", FData.HostName);
|
|
Storage->WriteString(L"UserName", FData.UserName);
|
|
Storage->WriteString(L"RemoteDirectory", FData.RemoteDirectory);
|
|
Storage->WriteString(L"LocalDirectory", FData.LocalDirectory);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TCopyParamRule::GetEmpty() const
|
|
{
|
|
return
|
|
FData.HostName.IsEmpty() &&
|
|
FData.UserName.IsEmpty() &&
|
|
FData.RemoteDirectory.IsEmpty() &&
|
|
FData.LocalDirectory.IsEmpty();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
UnicodeString __fastcall TCopyParamRule::GetInfoStr(UnicodeString Separator) const
|
|
{
|
|
UnicodeString Result;
|
|
#define ADD(FMT, ELEM) \
|
|
if (!FData.ELEM.IsEmpty()) \
|
|
Result += (Result.IsEmpty() ? UnicodeString() : Separator) + FMTLOAD(FMT, (FData.ELEM));
|
|
ADD(COPY_RULE_HOSTNAME, HostName);
|
|
ADD(COPY_RULE_USERNAME, UserName);
|
|
ADD(COPY_RULE_REMOTE_DIR, RemoteDirectory);
|
|
ADD(COPY_RULE_LOCAL_DIR, LocalDirectory);
|
|
#undef ADD
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
UnicodeString TCopyParamList::FInvalidChars(L"/\\[]");
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TCopyParamList::TCopyParamList()
|
|
{
|
|
Init();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TCopyParamList::Init()
|
|
{
|
|
FCopyParams = new TList();
|
|
FRules = new TList();
|
|
FNames = new TStringList();
|
|
FNameList = NULL;
|
|
FModified = false;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TCopyParamList::~TCopyParamList()
|
|
{
|
|
Clear();
|
|
delete FCopyParams;
|
|
delete FRules;
|
|
delete FNames;
|
|
delete FNameList;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TCopyParamList::Reset()
|
|
{
|
|
SAFE_DESTROY(FNameList);
|
|
FModified = false;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
void __fastcall TCopyParamList::Modify()
|
|
{
|
|
SAFE_DESTROY(FNameList);
|
|
FModified = true;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
void __fastcall TCopyParamList::ValidateName(const UnicodeString Name)
|
|
{
|
|
if (Name.LastDelimiter(FInvalidChars) > 0)
|
|
{
|
|
throw Exception(FMTLOAD(ITEM_NAME_INVALID, (Name, FInvalidChars)));
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
TCopyParamList & __fastcall TCopyParamList::operator=(const TCopyParamList & rhl)
|
|
{
|
|
Clear();
|
|
|
|
for (int Index = 0; Index < rhl.Count; Index++)
|
|
{
|
|
TCopyParamType * CopyParam = new TCopyParamType(*rhl.CopyParams[Index]);
|
|
TCopyParamRule * Rule = NULL;
|
|
if (rhl.Rules[Index] != NULL)
|
|
{
|
|
Rule = new TCopyParamRule(*rhl.Rules[Index]);
|
|
}
|
|
Add(rhl.Names[Index], CopyParam, Rule);
|
|
}
|
|
// there should be comparison of with the assigned list, but we rely on caller
|
|
// to do it instead (TGUIConfiguration::SetCopyParamList)
|
|
Modify();
|
|
return *this;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TCopyParamList::operator==(const TCopyParamList & rhl) const
|
|
{
|
|
bool Result = (Count == rhl.Count);
|
|
if (Result)
|
|
{
|
|
int i = 0;
|
|
while ((i < Count) && Result)
|
|
{
|
|
Result =
|
|
(Names[i] == rhl.Names[i]) &&
|
|
CompareItem(i, rhl.CopyParams[i], rhl.Rules[i]);
|
|
i++;
|
|
}
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TCopyParamList::IndexOfName(const UnicodeString Name) const
|
|
{
|
|
return FNames->IndexOf(Name);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TCopyParamList::CompareItem(int Index,
|
|
const TCopyParamType * CopyParam, const TCopyParamRule * Rule) const
|
|
{
|
|
return
|
|
((*CopyParams[Index]) == *CopyParam) &&
|
|
((Rules[Index] == NULL) ?
|
|
(Rule == NULL) :
|
|
((Rule != NULL) && (*Rules[Index]) == (*Rule)));
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TCopyParamList::Clear()
|
|
{
|
|
for (int i = 0; i < Count; i++)
|
|
{
|
|
delete CopyParams[i];
|
|
delete Rules[i];
|
|
}
|
|
FCopyParams->Clear();
|
|
FRules->Clear();
|
|
FNames->Clear();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TCopyParamList::Add(const UnicodeString Name,
|
|
TCopyParamType * CopyParam, TCopyParamRule * Rule)
|
|
{
|
|
Insert(Count, Name, CopyParam, Rule);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TCopyParamList::Insert(int Index, const UnicodeString Name,
|
|
TCopyParamType * CopyParam, TCopyParamRule * Rule)
|
|
{
|
|
DebugAssert(FNames->IndexOf(Name) < 0);
|
|
FNames->Insert(Index, Name);
|
|
DebugAssert(CopyParam != NULL);
|
|
FCopyParams->Insert(Index, reinterpret_cast<TObject *>(CopyParam));
|
|
FRules->Insert(Index, reinterpret_cast<TObject *>(Rule));
|
|
Modify();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TCopyParamList::Change(int Index, const UnicodeString Name,
|
|
TCopyParamType * CopyParam, TCopyParamRule * Rule)
|
|
{
|
|
if ((Name != Names[Index]) || !CompareItem(Index, CopyParam, Rule))
|
|
{
|
|
FNames->Strings[Index] = Name;
|
|
delete CopyParams[Index];
|
|
FCopyParams->Items[Index] = (reinterpret_cast<TObject *>(CopyParam));
|
|
delete Rules[Index];
|
|
FRules->Items[Index] = (reinterpret_cast<TObject *>(Rule));
|
|
Modify();
|
|
}
|
|
else
|
|
{
|
|
delete CopyParam;
|
|
delete Rule;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TCopyParamList::Move(int CurIndex, int NewIndex)
|
|
{
|
|
if (CurIndex != NewIndex)
|
|
{
|
|
FNames->Move(CurIndex, NewIndex);
|
|
FCopyParams->Move(CurIndex, NewIndex);
|
|
FRules->Move(CurIndex, NewIndex);
|
|
Modify();
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TCopyParamList::Delete(int Index)
|
|
{
|
|
DebugAssert((Index >= 0) && (Index < Count));
|
|
FNames->Delete(Index);
|
|
delete CopyParams[Index];
|
|
FCopyParams->Delete(Index);
|
|
delete Rules[Index];
|
|
FRules->Delete(Index);
|
|
Modify();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TCopyParamList::Find(const TCopyParamRuleData & Value) const
|
|
{
|
|
int Result = -1;
|
|
int i = 0;
|
|
while ((i < FRules->Count) && (Result < 0))
|
|
{
|
|
if (FRules->Items[i] != NULL)
|
|
{
|
|
if (Rules[i]->Matches(Value))
|
|
{
|
|
Result = i;
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TCopyParamList::Load(THierarchicalStorage * Storage, int ACount)
|
|
{
|
|
for (int Index = 0; Index < ACount; Index++)
|
|
{
|
|
UnicodeString Name = IntToStr(Index);
|
|
TCopyParamRule * Rule = NULL;
|
|
TCopyParamType * CopyParam = new TCopyParamType();
|
|
try
|
|
{
|
|
if (Storage->OpenSubKey(Name, false))
|
|
{
|
|
try
|
|
{
|
|
Name = Storage->ReadString(L"Name", Name);
|
|
CopyParam->Load(Storage);
|
|
|
|
if (Storage->ReadBool(L"HasRule", false))
|
|
{
|
|
Rule = new TCopyParamRule();
|
|
Rule->Load(Storage);
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
Storage->CloseSubKey();
|
|
}
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
delete CopyParam;
|
|
delete Rule;
|
|
throw;
|
|
}
|
|
|
|
FCopyParams->Add(reinterpret_cast<TObject *>(CopyParam));
|
|
FRules->Add(reinterpret_cast<TObject *>(Rule));
|
|
FNames->Add(Name);
|
|
}
|
|
Reset();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TCopyParamList::Save(THierarchicalStorage * Storage) const
|
|
{
|
|
Storage->ClearSubKeys();
|
|
for (int Index = 0; Index < Count; Index++)
|
|
{
|
|
if (Storage->OpenSubKey(IntToStr(Index), true))
|
|
{
|
|
try
|
|
{
|
|
const TCopyParamType * CopyParam = CopyParams[Index];
|
|
const TCopyParamRule * Rule = Rules[Index];
|
|
|
|
Storage->WriteString(L"Name", Names[Index]);
|
|
CopyParam->Save(Storage);
|
|
Storage->WriteBool(L"HasRule", (Rule != NULL));
|
|
if (Rule != NULL)
|
|
{
|
|
Rule->Save(Storage);
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
Storage->CloseSubKey();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TCopyParamList::GetCount() const
|
|
{
|
|
return FCopyParams->Count;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
const TCopyParamRule * __fastcall TCopyParamList::GetRule(int Index) const
|
|
{
|
|
return reinterpret_cast<TCopyParamRule *>(FRules->Items[Index]);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
const TCopyParamType * __fastcall TCopyParamList::GetCopyParam(int Index) const
|
|
{
|
|
return reinterpret_cast<TCopyParamType *>(FCopyParams->Items[Index]);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
UnicodeString __fastcall TCopyParamList::GetName(int Index) const
|
|
{
|
|
return FNames->Strings[Index];
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
TStrings * __fastcall TCopyParamList::GetNameList() const
|
|
{
|
|
if (FNameList == NULL)
|
|
{
|
|
FNameList = new TStringList();
|
|
|
|
for (int i = 0; i < Count; i++)
|
|
{
|
|
FNameList->Add(FNames->Strings[i]);
|
|
}
|
|
}
|
|
return FNameList;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TCopyParamList::GetAnyRule() const
|
|
{
|
|
bool Result = false;
|
|
int i = 0;
|
|
while ((i < Count) && !Result)
|
|
{
|
|
Result = (Rules[i] != NULL);
|
|
i++;
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TGUIConfiguration::TGUIConfiguration(): TConfiguration()
|
|
{
|
|
FLocale = 0;
|
|
SetAppliedLocale(InternalLocale(), UnicodeString());
|
|
FLocales = new TObjectList();
|
|
FLastLocalesExts = L"*";
|
|
FCopyParamList = new TCopyParamList();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TGUIConfiguration::~TGUIConfiguration()
|
|
{
|
|
delete FLocales;
|
|
delete FCopyParamList;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::Default()
|
|
{
|
|
TConfiguration::Default();
|
|
|
|
// reset before call to DefaultLocalized()
|
|
FDefaultCopyParam.Default();
|
|
|
|
FCopyParamListDefaults = true;
|
|
DefaultLocalized();
|
|
|
|
FIgnoreCancelBeforeFinish = TDateTime(0, 0, 3, 0);
|
|
FContinueOnError = false;
|
|
FConfirmCommandSession = true;
|
|
FSynchronizeParams = TTerminal::spDefault;
|
|
FSynchronizeModeAuto = -1;
|
|
FSynchronizeMode = TTerminal::smRemote;
|
|
FMaxWatchDirectories = 500;
|
|
FSynchronizeOptions = soRecurse | soSynchronizeAsk;
|
|
FQueueBootstrap = false;
|
|
FQueueKeepDoneItems = true;
|
|
FQueueKeepDoneItemsFor = 15;
|
|
FQueueAutoPopup = true;
|
|
FSessionRememberPassword = true;
|
|
UnicodeString ProgramsFolder;
|
|
KnownFolderPath(FOLDERID_ProgramFiles, ProgramsFolder);
|
|
FDefaultPuttyPathOnly = IncludeTrailingBackslash(ProgramsFolder) + L"PuTTY\\" + OriginalPuttyExecutable;
|
|
FDefaultPuttyPath = L"%ProgramFiles%\\PuTTY\\" + OriginalPuttyExecutable;
|
|
FPuttyPath = FormatCommand(FDefaultPuttyPath, L"");
|
|
FUsePuttyPwFile = asAuto;
|
|
FPuttyPassword = false;
|
|
FTelnetForFtpInPutty = true;
|
|
FPuttySession = L"WinSCP temporary session";
|
|
FBeepOnFinish = false;
|
|
FBeepOnFinishAfter = TDateTime(0, 0, 30, 0);
|
|
FBeepSound = L"SystemDefault";
|
|
FCopyParamCurrent = L"";
|
|
FKeepUpToDateChangeDelay = 500;
|
|
FChecksumAlg = L"sha1";
|
|
FSessionReopenAutoIdle = SessionReopenAutoIdleDefault;
|
|
FSessionReopenAutoIdleOn = true;
|
|
FSessionReopenAutoInactive = false;
|
|
FSessionSilentDisconnect = false;
|
|
|
|
FNewDirectoryProperties.Default();
|
|
FNewDirectoryProperties.Rights = TRights::rfDefault | TRights::rfExec;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::DefaultLocalized()
|
|
{
|
|
if (FCopyParamListDefaults)
|
|
{
|
|
FCopyParamList->Clear();
|
|
|
|
// guard against "empty resource string" from obsolete traslations
|
|
// (DefaultLocalized is called for the first time before detection of
|
|
// obsolete translations)
|
|
if (!LoadStr(COPY_PARAM_PRESET_ASCII).IsEmpty())
|
|
{
|
|
TCopyParamType * CopyParam;
|
|
|
|
CopyParam = new TCopyParamType(FDefaultCopyParam);
|
|
CopyParam->TransferMode = tmAscii;
|
|
FCopyParamList->Add(LoadStr(COPY_PARAM_PRESET_ASCII), CopyParam, NULL);
|
|
|
|
CopyParam = new TCopyParamType(FDefaultCopyParam);
|
|
CopyParam->TransferMode = tmBinary;
|
|
FCopyParamList->Add(LoadStr(COPY_PARAM_PRESET_BINARY), CopyParam, NULL);
|
|
|
|
CopyParam = new TCopyParamType(FDefaultCopyParam);
|
|
CopyParam->NewerOnly = true;
|
|
FCopyParamList->Add(LoadStr(COPY_PARAM_NEWER_ONLY), CopyParam, NULL);
|
|
|
|
CopyParam = new TCopyParamType(FDefaultCopyParam);
|
|
CopyParam->IncludeFileMask = TFileMasks(FORMAT(L"%s */", (IncludeExcludeFileMasksDelimiter)));
|
|
FCopyParamList->Add(LoadStr(COPY_PARAM_PRESET_EXCLUDE_ALL_DIR), CopyParam, NULL);
|
|
}
|
|
|
|
FCopyParamList->Reset();
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::UpdateStaticUsage()
|
|
{
|
|
TConfiguration::UpdateStaticUsage();
|
|
Usage->Set(L"CopyParamsCount", (FCopyParamListDefaults ? 0 : FCopyParamList->Count));
|
|
Usage->Set(L"Putty", ExtractProgramName(PuttyPath));
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
// duplicated from core\configuration.cpp
|
|
#define BLOCK(KEY, CANCREATE, BLOCK) \
|
|
if (Storage->OpenSubKeyPath(KEY, CANCREATE)) try { BLOCK } __finally { Storage->CloseSubKeyPath(); }
|
|
#define KEY(TYPE, VAR) KEYEX(TYPE, VAR, PropertyToKey(TEXT(#VAR)))
|
|
#define REGCONFIG(CANCREATE) \
|
|
BLOCK(L"Interface", CANCREATE, \
|
|
KEY(Bool, ContinueOnError); \
|
|
KEY(Bool, ConfirmCommandSession); \
|
|
KEY(Integer, SynchronizeParams); \
|
|
KEY(Integer, SynchronizeOptions); \
|
|
KEY(Integer, SynchronizeModeAuto); \
|
|
KEY(Integer, SynchronizeMode); \
|
|
KEY(Integer, MaxWatchDirectories); \
|
|
KEY(Bool, QueueBootstrap); \
|
|
KEY(Integer, QueueKeepDoneItems); \
|
|
KEY(Integer, QueueKeepDoneItemsFor); \
|
|
KEY(Bool, QueueAutoPopup); \
|
|
KEYEX(Bool, SessionRememberPassword, L"QueueRememberPassword"); \
|
|
KEY(String, PuttySession); \
|
|
KEY(String, PuttyPath); \
|
|
KEY(Enum, UsePuttyPwFile); \
|
|
KEY(Bool, PuttyPassword); \
|
|
KEY(Bool, TelnetForFtpInPutty); \
|
|
KEY(DateTime, IgnoreCancelBeforeFinish); \
|
|
KEY(Bool, BeepOnFinish); \
|
|
KEY(DateTime, BeepOnFinishAfter); \
|
|
KEY(String, BeepSound); \
|
|
KEY(Integer, KeepUpToDateChangeDelay); \
|
|
KEY(String, ChecksumAlg); \
|
|
KEY(Integer, SessionReopenAutoIdle); \
|
|
KEY(Bool, SessionReopenAutoIdleOn); \
|
|
KEY(Bool, SessionReopenAutoInactive); \
|
|
KEY(Bool, SessionSilentDisconnect); \
|
|
); \
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TGUIConfiguration::DoSaveCopyParam(THierarchicalStorage * Storage, const TCopyParamType * CopyParam, const TCopyParamType * Defaults)
|
|
{
|
|
bool Result = Storage->OpenSubKeyPath(L"Interface\\CopyParam", true);
|
|
if (Result)
|
|
{
|
|
CopyParam->Save(Storage, Defaults);
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::SaveData(THierarchicalStorage * Storage, bool All)
|
|
{
|
|
TConfiguration::SaveData(Storage, All);
|
|
|
|
// duplicated from core\configuration.cpp
|
|
#define KEYEX(TYPE, VAR, NAME) Storage->Write ## TYPE(NAME, VAR)
|
|
REGCONFIG(true);
|
|
#undef KEYEX
|
|
|
|
if (DoSaveCopyParam(Storage, &FDefaultCopyParam, NULL))
|
|
try
|
|
{
|
|
FDefaultCopyParam.Save(Storage);
|
|
|
|
if (FCopyParamListDefaults)
|
|
{
|
|
DebugAssert(!FCopyParamList->Modified);
|
|
Storage->WriteInteger(L"CopyParamList", -1);
|
|
}
|
|
else if (All || FCopyParamList->Modified)
|
|
{
|
|
Storage->WriteInteger(L"CopyParamList", FCopyParamList->Count);
|
|
FCopyParamList->Save(Storage);
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
Storage->CloseSubKeyPath();
|
|
}
|
|
|
|
if (Storage->OpenSubKeyPath(L"Interface\\NewDirectory2", true))
|
|
try
|
|
{
|
|
FNewDirectoryProperties.Save(Storage);
|
|
}
|
|
__finally
|
|
{
|
|
Storage->CloseSubKeyPath();
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TGUIConfiguration::LoadCopyParam(THierarchicalStorage * Storage, TCopyParamType * CopyParam)
|
|
{
|
|
bool Result =
|
|
Storage->OpenSubKeyPath(L"Interface\\CopyParam", false);
|
|
if (Result)
|
|
{
|
|
try
|
|
{
|
|
CopyParam->Load(Storage);
|
|
}
|
|
catch (...)
|
|
{
|
|
Storage->CloseSubKeyPath();
|
|
throw;
|
|
}
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::LoadDefaultCopyParam(THierarchicalStorage * Storage)
|
|
{
|
|
FDefaultCopyParam.Load(Storage);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::LoadData(THierarchicalStorage * Storage)
|
|
{
|
|
TConfiguration::LoadData(Storage);
|
|
|
|
// duplicated from core\configuration.cpp
|
|
#define KEYEX(TYPE, VAR, NAME) VAR = Storage->Read ## TYPE(NAME, VAR)
|
|
#pragma warn -eas
|
|
REGCONFIG(false);
|
|
#pragma warn +eas
|
|
#undef KEYEX
|
|
|
|
// FDefaultCopyParam must be loaded before eventual setting defaults for CopyParamList
|
|
if (LoadCopyParam(Storage, &FDefaultCopyParam))
|
|
try
|
|
{
|
|
int CopyParamListCount = Storage->ReadInteger(L"CopyParamList", -1);
|
|
FCopyParamListDefaults = (CopyParamListCount < 0);
|
|
if (!FCopyParamListDefaults)
|
|
{
|
|
FCopyParamList->Clear();
|
|
FCopyParamList->Load(Storage, CopyParamListCount);
|
|
}
|
|
else if (FCopyParamList->Modified)
|
|
{
|
|
FCopyParamList->Clear();
|
|
FCopyParamListDefaults = false;
|
|
}
|
|
FCopyParamList->Reset();
|
|
}
|
|
__finally
|
|
{
|
|
Storage->CloseSubKeyPath();
|
|
}
|
|
|
|
// Make it compatible with versions prior to 3.7.1 that have not saved PuttyPath
|
|
// with quotes. First check for absence of quotes.
|
|
// Add quotes either if the path is set to default putty path (even if it does
|
|
// not exists) or when the path points to existing file (so there are no parameters
|
|
// yet in the string). Note that FileExists may display error dialog, but as
|
|
// it should be called only for custom users path, let's expect that the user
|
|
// can take care of it.
|
|
if ((FPuttyPath.SubString(1, 1) != L"\"") &&
|
|
(IsPathToSameFile(ExpandEnvironmentVariables(FPuttyPath), FDefaultPuttyPathOnly) ||
|
|
FileExists(ApiPath(ExpandEnvironmentVariables(FPuttyPath)))))
|
|
{
|
|
FPuttyPath = FormatCommand(FPuttyPath, L"");
|
|
}
|
|
|
|
if (Storage->OpenSubKeyPath(L"Interface\\NewDirectory2", false))
|
|
try
|
|
{
|
|
FNewDirectoryProperties.Load(Storage);
|
|
}
|
|
__finally
|
|
{
|
|
Storage->CloseSubKeyPath();
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::Saved()
|
|
{
|
|
TConfiguration::Saved();
|
|
|
|
FCopyParamList->Reset();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
UnicodeString __fastcall TGUIConfiguration::GetTranslationModule(const UnicodeString & Path)
|
|
{
|
|
UnicodeString SubPath =
|
|
TPath::Combine(TPath::Combine(ExtractFilePath(Path), TranslationsSubFolder), ExtractFileName(Path));
|
|
UnicodeString Result;
|
|
// Prefer the SubPath. Default to SubPath.
|
|
if (FileExists(Path) && !FileExists(SubPath))
|
|
{
|
|
Result = Path;
|
|
}
|
|
else
|
|
{
|
|
Result = SubPath;
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HMODULE TGUIConfiguration::LoadNewResourceModule(LCID ALocale, UnicodeString & FileName)
|
|
{
|
|
UnicodeString LibraryFileName;
|
|
HMODULE NewInstance = 0;
|
|
LCID AInternalLocale = InternalLocale();
|
|
bool Internal = (ALocale == AInternalLocale);
|
|
DWORD PrimaryLang = PRIMARYLANGID(ALocale);
|
|
if (!Internal)
|
|
{
|
|
UnicodeString Module;
|
|
UnicodeString LocaleName;
|
|
|
|
Module = ModuleFileName();
|
|
if ((ALocale & AdditionalLanguageMask) != AdditionalLanguageMask)
|
|
{
|
|
wchar_t LocaleStr[4];
|
|
GetLocaleInfo(ALocale, LOCALE_SABBREVLANGNAME, LocaleStr, std::size(LocaleStr));
|
|
LocaleName = LocaleStr;
|
|
DebugAssert(!LocaleName.IsEmpty());
|
|
}
|
|
else
|
|
{
|
|
LocaleName = AdditionalLanguagePrefix +
|
|
char(ALocale & ~AdditionalLanguageMask);
|
|
}
|
|
|
|
Module = ChangeFileExt(Module, UnicodeString(L".") + LocaleName);
|
|
// Look for a potential language/country translation
|
|
UnicodeString ModulePath = GetTranslationModule(Module);
|
|
NewInstance = LoadLibraryEx(ModulePath.c_str(), 0, LOAD_LIBRARY_AS_DATAFILE);
|
|
if (NewInstance)
|
|
{
|
|
LibraryFileName = ModulePath;
|
|
}
|
|
else
|
|
{
|
|
DWORD SubLang = SUBLANGID(ALocale);
|
|
DebugAssert(SUBLANG_DEFAULT == SUBLANG_CHINESE_TRADITIONAL);
|
|
// Finally look for a language-only translation.
|
|
// But for Chinese, never use "traditional" (what is the "default" Chinese), if we want "Simplified"
|
|
// (the same what Inno Setup does)
|
|
if ((PrimaryLang != LANG_CHINESE) ||
|
|
(SubLang == SUBLANG_CHINESE_TRADITIONAL))
|
|
{
|
|
Module.SetLength(Module.Length() - 1);
|
|
ModulePath = GetTranslationModule(Module);
|
|
NewInstance = LoadLibraryEx(ModulePath.c_str(), 0, LOAD_LIBRARY_AS_DATAFILE);
|
|
if (NewInstance)
|
|
{
|
|
LibraryFileName = ModulePath;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the locale is non-US English and we do not have that translation (and it's unlikely we ever have),
|
|
// treat it as if it were US English.
|
|
if (!NewInstance && !Internal && (PrimaryLang == static_cast<DWORD>(PRIMARYLANGID(AInternalLocale))))
|
|
{
|
|
Internal = true;
|
|
}
|
|
|
|
if (!NewInstance && !Internal)
|
|
{
|
|
throw Exception(FMTLOAD(LOCALE_LOAD_ERROR, (int(ALocale))));
|
|
}
|
|
else
|
|
{
|
|
if (Internal)
|
|
{
|
|
NewInstance = HInstance;
|
|
}
|
|
}
|
|
|
|
FileName = LibraryFileName;
|
|
|
|
return NewInstance;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
LCID __fastcall TGUIConfiguration::InternalLocale()
|
|
{
|
|
LCID Result;
|
|
if (GetTranslationCount(ApplicationInfo) > 0)
|
|
{
|
|
TTranslation Translation;
|
|
Translation = GetTranslation(ApplicationInfo, 0);
|
|
Result = MAKELANGID(PRIMARYLANGID(Translation.Language), SUBLANG_DEFAULT);
|
|
}
|
|
else
|
|
{
|
|
DebugFail();
|
|
Result = 0;
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
LCID __fastcall TGUIConfiguration::GetLocale()
|
|
{
|
|
return FLocale;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::SetLocale(LCID value)
|
|
{
|
|
if (Locale != value)
|
|
{
|
|
SetLocaleInternal(value, false, false);
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::SetLocaleSafe(LCID value)
|
|
{
|
|
if (Locale != value)
|
|
{
|
|
SetLocaleInternal(value, true, false);
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
UnicodeString __fastcall TGUIConfiguration::GetAppliedLocaleHex()
|
|
{
|
|
return IntToHex(__int64(AppliedLocale), 4);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int TGUIConfiguration::GetResourceModuleCompleteness(HMODULE /*Module*/)
|
|
{
|
|
return 100;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool TGUIConfiguration::IsTranslationComplete(HMODULE /*Module*/)
|
|
{
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::SetLocaleInternal(LCID value, bool Safe, bool CompleteOnly)
|
|
{
|
|
LCID L = value;
|
|
if (L == NULL)
|
|
{
|
|
L = GetUserDefaultUILanguage();
|
|
}
|
|
|
|
HMODULE Module = NULL;
|
|
UnicodeString FileName;
|
|
|
|
try
|
|
{
|
|
Module = LoadNewResourceModule(L, FileName);
|
|
DebugAssert(Module != NULL);
|
|
if (CompleteOnly && !IsTranslationComplete(Module))
|
|
{
|
|
Abort();
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
if (Module != NULL)
|
|
{
|
|
FreeResourceModule(Module);
|
|
Module = NULL;
|
|
}
|
|
|
|
if (Safe)
|
|
{
|
|
// ignore any exception while loading locale
|
|
}
|
|
else
|
|
{
|
|
throw;
|
|
}
|
|
}
|
|
|
|
if (Module != NULL)
|
|
{
|
|
FLocale = value;
|
|
if (CanApplyLocaleImmediately)
|
|
{
|
|
SetAppliedLocale(L, FileName);
|
|
SetResourceModule(Module);
|
|
ResStringCleanupCache();
|
|
}
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TGUIConfiguration::GetCanApplyLocaleImmediately()
|
|
{
|
|
return
|
|
(Screen->FormCount == 0) &&
|
|
(Screen->DataModuleCount == 0);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TGUIConfiguration::UsingInternalTranslation()
|
|
{
|
|
return FLocaleModuleName.IsEmpty();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
UnicodeString __fastcall TGUIConfiguration::AppliedLocaleCopyright()
|
|
{
|
|
UnicodeString Result;
|
|
if (UsingInternalTranslation())
|
|
{
|
|
DebugFail(); // we do not expect to get called with internal locale
|
|
Result = UnicodeString();
|
|
}
|
|
else
|
|
{
|
|
Result = GetFileFileInfoString(L"LegalCopyright", FLocaleModuleName);
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
UnicodeString __fastcall TGUIConfiguration::AppliedLocaleVersion()
|
|
{
|
|
UnicodeString Result;
|
|
if (UsingInternalTranslation())
|
|
{
|
|
// noop
|
|
}
|
|
else
|
|
{
|
|
Result = GetFileVersion(FLocaleModuleName);
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::SetAppliedLocale(LCID AppliedLocale, const UnicodeString & LocaleModuleName)
|
|
{
|
|
FAppliedLocale = AppliedLocale;
|
|
FLocaleModuleName = LocaleModuleName;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void TGUIConfiguration::FreeResourceModule(HMODULE Instance)
|
|
{
|
|
TLibModule * MainModule = FindModule(HInstance);
|
|
DebugAssert(sizeof(Instance) == sizeof(MainModule->Instance));
|
|
if (Instance != reinterpret_cast<HMODULE>(MainModule->Instance))
|
|
{
|
|
FreeLibrary(Instance);
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HMODULE TGUIConfiguration::ChangeToDefaultResourceModule()
|
|
{
|
|
return ChangeResourceModule(NULL);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HINSTANCE TGUIConfiguration::ChangeResourceModule(HMODULE Instance)
|
|
{
|
|
if (Instance == NULL)
|
|
{
|
|
Instance = HInstance;
|
|
}
|
|
TLibModule * MainModule = FindModule(HInstance);
|
|
HMODULE Result = reinterpret_cast<HMODULE>(MainModule->ResInstance);
|
|
MainModule->ResInstance = reinterpret_cast<HINST>(Instance);
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void TGUIConfiguration::SetResourceModule(HMODULE Instance)
|
|
{
|
|
HMODULE PrevHandle = ChangeResourceModule(Instance);
|
|
FreeResourceModule(PrevHandle);
|
|
|
|
DefaultLocalized();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::FindLocales(const UnicodeString & Path, TStrings * Exts, UnicodeString & LocalesExts)
|
|
{
|
|
int FindAttrs = faReadOnly | faArchive;
|
|
|
|
TSearchRecOwned SearchRec;
|
|
UnicodeString BaseName = ChangeFileExt(ExtractFileName(ModuleFileName()), L".");
|
|
UnicodeString LocalesMask = TPath::Combine(Path, BaseName + L"*");
|
|
bool Found = (FindFirstUnchecked(LocalesMask, FindAttrs, SearchRec) == 0);
|
|
while (Found)
|
|
{
|
|
if (DebugAlwaysTrue(SameText(BaseName, LeftStr(SearchRec.Name, BaseName.Length()))))
|
|
{
|
|
UnicodeString Ext = MidStr(SearchRec.Name, BaseName.Length() + 1).UpperCase();
|
|
// DLL is a remnant from times the .NET assembly was winscp.dll, not winscpnet.dll.
|
|
if ((Ext.Length() >= 2) && (Ext.Length() <= 3) &&
|
|
(Ext != L"EXE") && (Ext != L"COM") && (Ext != L"DLL") && (Ext != L"INI") && (Ext != L"MAP"))
|
|
{
|
|
LocalesExts += Ext + L",";
|
|
Exts->Add(Ext);
|
|
}
|
|
}
|
|
Found = (FindNextChecked(SearchRec) == 0);
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::AddLocale(LCID Locale, const UnicodeString & AName)
|
|
{
|
|
UnicodeString Name = AName;
|
|
|
|
if (Name.IsEmpty())
|
|
{
|
|
wchar_t LocaleStr[255];
|
|
GetLocaleInfo(Locale, LOCALE_SENGLANGUAGE, LocaleStr, std::size(LocaleStr));
|
|
Name = UnicodeString(LocaleStr) + TitleSeparator;
|
|
// LOCALE_SNATIVELANGNAME
|
|
GetLocaleInfo(Locale, LOCALE_SLANGUAGE, LocaleStr, std::size(LocaleStr));
|
|
Name += LocaleStr;
|
|
}
|
|
|
|
std::unique_ptr<TLocaleInfo> LocaleInfo(new TLocaleInfo());
|
|
LocaleInfo->Locale = Locale;
|
|
LocaleInfo->Name = Name;
|
|
|
|
try
|
|
{
|
|
UnicodeString FileName;
|
|
HINSTANCE Module = LoadNewResourceModule(Locale, FileName);
|
|
try
|
|
{
|
|
LocaleInfo->Completeness = GetResourceModuleCompleteness(Module);
|
|
}
|
|
__finally
|
|
{
|
|
FreeResourceModule(Module);
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
LocaleInfo->Completeness = -1;
|
|
}
|
|
|
|
FLocales->Add(LocaleInfo.release());
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TGUIConfiguration::LocalesCompare(void * Item1, void * Item2)
|
|
{
|
|
TLocaleInfo * LocaleInfo1 = static_cast<TLocaleInfo *>(Item1);
|
|
TLocaleInfo * LocaleInfo2 = static_cast<TLocaleInfo *>(Item2);
|
|
return CompareText(LocaleInfo1->Name, LocaleInfo2->Name);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
TObjectList * __fastcall TGUIConfiguration::GetLocales()
|
|
{
|
|
UnicodeString LocalesPath = ExtractFilePath(ModuleFileName());
|
|
UnicodeString SubLocalesPath = TPath::Combine(LocalesPath, TranslationsSubFolder);
|
|
|
|
UnicodeString LocalesExts;
|
|
std::unique_ptr<TStringList> Exts(CreateSortedStringList());
|
|
FindLocales(LocalesPath, Exts.get(), LocalesExts);
|
|
FindLocales(SubLocalesPath, Exts.get(), LocalesExts);
|
|
|
|
if (FLastLocalesExts != LocalesExts)
|
|
{
|
|
FLastLocalesExts = LocalesExts;
|
|
FLocales->Clear();
|
|
|
|
AddLocale(InternalLocale(), EmptyStr);
|
|
|
|
TLanguages * Langs = Languages();
|
|
int Count = Langs->Count;
|
|
|
|
typedef std::map<UnicodeString, std::pair<int, DWORD> > TConflicts;
|
|
TConflicts DefaultLangConflicts;
|
|
LCID InvalidLocale = static_cast<LCID>(-1);
|
|
|
|
// The two-leter Windows code is not actually unique among languages.
|
|
// So find any duplicities and resolve them to the language, where ISO code also match.
|
|
// Notably:
|
|
// Georgian KAT ka-GE - Kalaallisut KAL kl-GL
|
|
// Tamil TAI ta-IN - Tajik TAJ tj-TJ
|
|
for (int Index = 0; Index < Count; Index++)
|
|
{
|
|
LCID Locale = Langs->LocaleID[Index];
|
|
DWORD SubLang = SUBLANGID(Locale);
|
|
if (SubLang == SUBLANG_DEFAULT)
|
|
{
|
|
UnicodeString LangExt2 = LeftStr(Langs->Ext[Index].UpperCase(), 2);
|
|
TConflicts::iterator Conflict = DefaultLangConflicts.find(LangExt2);
|
|
if (Conflict == DefaultLangConflicts.end())
|
|
{
|
|
Conflict = DefaultLangConflicts.insert(std::make_pair(LangExt2, std::make_pair(1, InvalidLocale))).first;
|
|
}
|
|
else
|
|
{
|
|
Conflict->second.first++;
|
|
}
|
|
|
|
UnicodeString LangName = CopyToChar(Langs->LocaleName[Index], L'-', false);
|
|
bool Matches = SameText(LangName, LangExt2);
|
|
if (Matches)
|
|
{
|
|
Conflict->second.second = Locale;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int Index = 0; Index < Count; Index++)
|
|
{
|
|
LCID Locale = Langs->LocaleID[Index];
|
|
DWORD SubLang = SUBLANGID(Locale);
|
|
UnicodeString LangExt3 = Langs->Ext[Index].UpperCase();
|
|
int Ext = Exts->IndexOf(LangExt3);
|
|
if ((Ext < 0) && (SubLang == SUBLANG_DEFAULT))
|
|
{
|
|
UnicodeString LangExt2 = LeftStr(LangExt3, 2);
|
|
TConflicts::const_iterator DefaultLangConflict = DefaultLangConflicts.find(LangExt2);
|
|
// Unless it is a conflicting extension with no resolution or resolved to another locale
|
|
if ((DefaultLangConflict == DefaultLangConflicts.end()) ||
|
|
(DefaultLangConflict->second.first == 1) ||
|
|
((DefaultLangConflict->second.second != InvalidLocale) &&
|
|
(DefaultLangConflict->second.second == Locale)))
|
|
{
|
|
Ext = Exts->IndexOf(LangExt2);
|
|
}
|
|
}
|
|
|
|
if ((Ext >= 0) && DebugAlwaysTrue(Exts->Objects[Ext] == NULL))
|
|
{
|
|
Exts->Objects[Ext] = reinterpret_cast<TObject*>(Locale);
|
|
AddLocale(Locale, EmptyStr);
|
|
}
|
|
}
|
|
|
|
for (int Index = 0; Index < Exts->Count; Index++)
|
|
{
|
|
if ((Exts->Objects[Index] == NULL) &&
|
|
(Exts->Strings[Index].Length() == 3) &&
|
|
SameText(Exts->Strings[Index].SubString(1, 2), AdditionalLanguagePrefix))
|
|
{
|
|
UnicodeString ModulePath = ChangeFileExt(ModuleFileName(), UnicodeString(L".") + Exts->Strings[Index]);
|
|
ModulePath = GetTranslationModule(ModulePath);
|
|
UnicodeString LangName = GetFileFileInfoString(L"LangName", ModulePath);
|
|
if (!LangName.IsEmpty())
|
|
{
|
|
AddLocale(AdditionalLanguageMask + UnicodeString(Exts->Strings[Index])[3], LangName);
|
|
}
|
|
}
|
|
}
|
|
|
|
FLocales->Sort(LocalesCompare);
|
|
}
|
|
|
|
return FLocales;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::SetDefaultCopyParam(const TGUICopyParamType & value)
|
|
{
|
|
FDefaultCopyParam.Assign(&value);
|
|
Changed();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TGUIConfiguration::GetRememberPassword()
|
|
{
|
|
bool Result = SessionRememberPassword || PuttyPassword;
|
|
|
|
if (!Result)
|
|
{
|
|
try
|
|
{
|
|
TRemoteCustomCommand RemoteCustomCommand;
|
|
TInteractiveCustomCommand InteractiveCustomCommand(&RemoteCustomCommand);
|
|
UnicodeString APuttyPath = InteractiveCustomCommand.Complete(PuttyPath, false);
|
|
Result = RemoteCustomCommand.IsPasswordCommand(PuttyPath);
|
|
}
|
|
catch (...)
|
|
{
|
|
// noop
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
const TCopyParamList * __fastcall TGUIConfiguration::GetCopyParamList()
|
|
{
|
|
return FCopyParamList;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::SetCopyParamList(const TCopyParamList * value)
|
|
{
|
|
if (!(*FCopyParamList == *value))
|
|
{
|
|
*FCopyParamList = *value;
|
|
FCopyParamListDefaults = false;
|
|
Changed();
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int __fastcall TGUIConfiguration::GetCopyParamIndex()
|
|
{
|
|
int Result;
|
|
if (FCopyParamCurrent.IsEmpty())
|
|
{
|
|
Result = -1;
|
|
}
|
|
else
|
|
{
|
|
Result = FCopyParamList->IndexOfName(FCopyParamCurrent);
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::SetCopyParamIndex(int value)
|
|
{
|
|
UnicodeString Name;
|
|
if (value < 0)
|
|
{
|
|
Name = L"";
|
|
}
|
|
else
|
|
{
|
|
Name = FCopyParamList->Names[value];
|
|
}
|
|
CopyParamCurrent = Name;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::SetCopyParamCurrent(UnicodeString value)
|
|
{
|
|
SET_CONFIG_PROPERTY(CopyParamCurrent);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
TGUICopyParamType __fastcall TGUIConfiguration::GetCurrentCopyParam()
|
|
{
|
|
return CopyParamPreset[CopyParamCurrent];
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
TGUICopyParamType __fastcall TGUIConfiguration::GetCopyParamPreset(UnicodeString Name)
|
|
{
|
|
TGUICopyParamType Result = FDefaultCopyParam;
|
|
if (!Name.IsEmpty())
|
|
{
|
|
int Index = FCopyParamList->IndexOfName(Name);
|
|
DebugAssert(Index >= 0);
|
|
if (Index >= 0)
|
|
{
|
|
const TCopyParamType * Preset = FCopyParamList->CopyParams[Index];
|
|
DebugAssert(Preset != NULL);
|
|
Result.Assign(Preset); // overwrite all but GUI options
|
|
// reset all options known not to be configurable per-preset
|
|
// kind of hack
|
|
Result.ResumeSupport = FDefaultCopyParam.ResumeSupport;
|
|
Result.ResumeThreshold = FDefaultCopyParam.ResumeThreshold;
|
|
Result.LocalInvalidChars = FDefaultCopyParam.LocalInvalidChars;
|
|
}
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TGUIConfiguration::GetHasCopyParamPreset(UnicodeString Name)
|
|
{
|
|
return Name.IsEmpty() || (FCopyParamList->IndexOfName(Name) >= 0);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::SetNewDirectoryProperties(
|
|
const TRemoteProperties & value)
|
|
{
|
|
SET_CONFIG_PROPERTY(NewDirectoryProperties);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::SetQueueBootstrap(bool value)
|
|
{
|
|
SET_CONFIG_PROPERTY(QueueBootstrap);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::SetQueueKeepDoneItems(bool value)
|
|
{
|
|
SET_CONFIG_PROPERTY(QueueKeepDoneItems);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TGUIConfiguration::SetQueueKeepDoneItemsFor(int value)
|
|
{
|
|
SET_CONFIG_PROPERTY(QueueKeepDoneItemsFor);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
TStoredSessionList * __fastcall TGUIConfiguration::SelectPuttySessionsForImport(
|
|
const UnicodeString & RootKey, const UnicodeString & Source, TStoredSessionList * Sessions, UnicodeString & Error)
|
|
{
|
|
std::unique_ptr<TStoredSessionList> ImportSessionList(new TStoredSessionList(true));
|
|
ImportSessionList->DefaultSettings = Sessions->DefaultSettings;
|
|
|
|
UnicodeString SessionsKey = GetPuttySessionsKey(RootKey);
|
|
std::unique_ptr<TRegistryStorage> Storage(new TRegistryStorage(SessionsKey));
|
|
Storage->ConfigureForPutty();
|
|
if (Storage->OpenRootKey(false))
|
|
{
|
|
ImportSessionList->Load(Storage.get(), false, true, true);
|
|
}
|
|
|
|
TSessionData * PuttySessionData =
|
|
static_cast<TSessionData *>(ImportSessionList->FindByName(PuttySession));
|
|
if (PuttySessionData != NULL)
|
|
{
|
|
ImportSessionList->Remove(PuttySessionData);
|
|
}
|
|
UnicodeString NoSessionsError = FMTLOAD(PUTTY_NO_SITES2, (Source, SessionsKey));
|
|
SelectSessionsToImportIfAny(ImportSessionList.get(), Sessions, Error, NoSessionsError);
|
|
|
|
return ImportSessionList.release();
|
|
}
|
|
//---------------------------------------------------------------------
|
|
bool __fastcall TGUIConfiguration::AnyPuttySessionForImport(TStoredSessionList * Sessions)
|
|
{
|
|
try
|
|
{
|
|
UnicodeString Error;
|
|
std::unique_ptr<TStoredSessionList> SessionsForImport(
|
|
SelectPuttySessionsForImport(OriginalPuttyRegistryStorageKey, L"PuTTY", Sessions, Error));
|
|
return (SessionsForImport->Count > 0);
|
|
}
|
|
catch (...)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|