In the FileZilla Client, the Windows version defaults to saving the configuration files -- i.e., filezilla.xml, layout.xml, and recentservers.xml -- to the %APPDATA%\FileZilla directory (or the current directory of the filezilla.exe executable if (and only if) for some reason the aforementioned directory fails.) On the Linux version, however, it checks if the $XDG_CONFIG_HOME environment variable is defined, followed by the $HOME/.config and $HOME/filezilla directories respectively. And if found, it looks like it tries to use the $XDG_CONFIG_HOME/filezilla directory as the preferred one.
For that reason, I am wondering why is there not a similar behaviour in the Windows version? In the case of the installed version, it makes perfect sense to use the %APPDATA%\FileZilla directory; however, when using the ‘portable’ (.zip) version, there should at least be some flexibility via a specific environment variable or the like. Case in point, if a user has FileZilla on a USB drive and uses it on PC 1, the configuration and preferences are saved locally; and consequently, when said user moves his or her USB drive to a different PC, the settings are left behind on the previous PC.
With that said, I propose having an environment variable -- e.g., FZ_CONFIG_ROOT -- in Windows that could be checked and used as the directory for saving configuration files. Looking at source code -- specifically in the commonui\fz_paths.cpp file, I think that it would be fairly easily to make this tweak. While I am not a proper developer, I took a stab at updating the existing code (as seen below.)
[ fz_paths.cpp ]
Code: Select all
#ifndef FZ_WINDOWS
namespace {
static std::wstring TryDirectory(std::wstring path, std::wstring const& suffix, bool check_exists)
{
if (!path.empty() && path[0] == '/') {
if (path[path.size() - 1] != '/') {
path += '/';
}
path += suffix;
if (check_exists) {
if (!CLocalPath(path).Exists(nullptr)) {
path.clear();
}
}
}
else {
path.clear();
}
return path;
}
}
// BEGIN ADDED SECTION.
#else
namespace {
static std::wstring TryDirectory(std::wstring path, std::wstring const& suffix, bool check_exists)
{
if (!path.empty()) {
if (path[path.size() - 1] == '\\') {
path = path.substr(0, path.size() - 1);
if (check_exists) {
if (!CLocalPath(path).Exists(nullptr)) {
path.clear();
}
}
}
}
else {
path.clear();
}
return path;
}
}
// END ADDED SECTION.
#endif
[ … ]
CLocalPath GetUnadjustedSettingsDir()
{
CLocalPath ret;
#ifdef FZ_WINDOWS
wchar_t* out{};
// BEGIN ADDED SECTION.
// Check if the user has set the FZ_CONFIG_ROOT environment variable.
if ( GetEnv("FZ_CONFIG_ROOT") != null )
{
std::wstring cfg = TryDirectory(GetEnv("FZ_CONFIG_ROOT"), L"", true); // check if the path truly exists.
if (!cfg.empty()) { // if it does, set it and append the '.config' subdirectory to the specified root.
std:wstring const& dir = cfg;
ret.SetPath(dir);
ret.AddSegment(L".config");
}
}
if ( ret.empty() ) // If the FZ_CONFIG_ROOT environment variable is not set or the specified path does not exist
{ // (or if running the installed version of Filezilla), proceed with the normal %APPDATA% path.
// END ADDED SECTION.
if (SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, 0, &out) == S_OK) {
ret.SetPath(out);
CoTaskMemFree(out);
}
if (!ret.empty()) {
ret.AddSegment(L"FileZilla");
}
}
if (ret.empty()) {
// Fall back to directory where the executable is
std::wstring const& dir = GetOwnExecutableDir();
ret.SetPath(dir);
}
#else
std::wstring cfg = TryDirectory(GetEnv("XDG_CONFIG_HOME"), L"filezilla/", true);
if (cfg.empty()) {
cfg = TryDirectory(GetEnv("HOME"), L".config/filezilla/", true);
}
if (cfg.empty()) {
cfg = TryDirectory(GetEnv("HOME"), L".filezilla/", true);
}
if (cfg.empty()) {
cfg = TryDirectory(GetEnv("XDG_CONFIG_HOME"), L"filezilla/", false);
}
if (cfg.empty()) {
cfg = TryDirectory(GetEnv("HOME"), L".config/filezilla/", false);
}
if (cfg.empty()) {
cfg = TryDirectory(GetEnv("HOME"), L".filezilla/", false);
}
ret.SetPath(cfg);
#endif
return ret;
}
[ … ]
Thanks and regards,
iambesi