2022-01-20 18:27:56 +00:00
|
|
|
// This file Copyright © 2009-2022 Mnemosyne LLC.
|
2022-02-07 16:25:02 +00:00
|
|
|
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
2022-01-20 18:27:56 +00:00
|
|
|
// or any future license endorsed by Mnemosyne LLC.
|
|
|
|
// License text can be found in the licenses/ folder.
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2021-12-16 22:58:58 +00:00
|
|
|
#include <algorithm>
|
2022-07-23 01:10:02 +00:00
|
|
|
#include <array>
|
|
|
|
#include <iterator>
|
2021-09-27 13:45:21 +00:00
|
|
|
#include <list>
|
|
|
|
#include <string>
|
2021-12-16 22:58:58 +00:00
|
|
|
#include <string_view>
|
2022-01-31 23:05:35 +00:00
|
|
|
#include <vector>
|
2012-12-27 19:39:44 +00:00
|
|
|
|
2014-09-21 18:03:13 +00:00
|
|
|
#ifdef __HAIKU__
|
2017-04-19 12:04:45 +00:00
|
|
|
#include <limits.h> /* PATH_MAX */
|
2014-09-21 18:03:13 +00:00
|
|
|
#endif
|
2013-07-08 17:07:31 +00:00
|
|
|
|
2014-07-04 00:00:07 +00:00
|
|
|
#ifdef _WIN32
|
2017-04-21 07:40:57 +00:00
|
|
|
#include <process.h> /* _beginthreadex(), _endthreadex() */
|
2017-04-19 12:04:45 +00:00
|
|
|
#include <windows.h>
|
2017-04-21 07:40:57 +00:00
|
|
|
#include <shlobj.h> /* SHGetKnownFolderPath(), FOLDERID_... */
|
2007-07-30 15:27:52 +00:00
|
|
|
#else
|
2022-04-05 01:37:12 +00:00
|
|
|
#include <pwd.h>
|
2014-12-13 15:22:39 +00:00
|
|
|
#include <unistd.h> /* getuid() */
|
2022-01-31 19:34:04 +00:00
|
|
|
#endif
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
#ifdef BUILD_MAC_CLIENT
|
|
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
|
|
#endif
|
2022-01-31 19:34:04 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
#ifdef __HAIKU__
|
|
|
|
#include <FindDirectory.h>
|
|
|
|
#endif
|
2007-07-30 15:27:52 +00:00
|
|
|
|
2022-04-07 22:26:59 +00:00
|
|
|
#include <fmt/format.h>
|
2022-03-14 04:43:35 +00:00
|
|
|
|
2006-07-16 19:39:23 +00:00
|
|
|
#include "transmission.h"
|
2022-01-31 19:34:04 +00:00
|
|
|
|
2014-07-08 00:08:43 +00:00
|
|
|
#include "file.h"
|
2013-01-25 23:34:20 +00:00
|
|
|
#include "log.h"
|
2007-07-31 14:26:44 +00:00
|
|
|
#include "platform.h"
|
2014-07-08 00:08:43 +00:00
|
|
|
#include "session.h"
|
2017-06-08 07:24:12 +00:00
|
|
|
#include "tr-assert.h"
|
2014-09-21 18:03:13 +00:00
|
|
|
#include "utils.h"
|
2007-07-30 15:27:52 +00:00
|
|
|
|
2021-11-13 00:10:04 +00:00
|
|
|
using namespace std::literals;
|
|
|
|
|
2007-07-30 15:27:52 +00:00
|
|
|
/***
|
|
|
|
**** PATHS
|
|
|
|
***/
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2014-09-21 18:03:13 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
static std::string win32_get_known_folder_ex(REFKNOWNFOLDERID folder_id, DWORD flags)
|
2014-09-21 18:03:13 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
PWSTR path;
|
2015-04-10 22:15:41 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (SHGetKnownFolderPath(folder_id, flags | KF_FLAG_DONT_UNEXPAND, nullptr, &path) == S_OK)
|
2015-04-10 22:15:41 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
auto* utf8_cstr = tr_win32_native_to_utf8(path, -1);
|
|
|
|
auto ret = std::string{ utf8_cstr };
|
|
|
|
tr_free(utf8_cstr);
|
2017-04-19 12:04:45 +00:00
|
|
|
CoTaskMemFree(path);
|
2022-07-23 01:10:02 +00:00
|
|
|
return ret;
|
2015-04-10 22:15:41 +00:00
|
|
|
}
|
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
return {};
|
2014-09-21 18:03:13 +00:00
|
|
|
}
|
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
static auto win32_get_known_folder(REFKNOWNFOLDERID folder_id)
|
2016-09-21 20:56:03 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
return win32_get_known_folder_ex(folder_id, KF_FLAG_DONT_VERIFY);
|
2016-09-21 20:56:03 +00:00
|
|
|
}
|
|
|
|
|
2014-09-21 18:03:13 +00:00
|
|
|
#endif
|
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
static std::string getHomeDir()
|
2006-10-13 06:29:26 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
if (auto* const dir = tr_env_get_string("HOME", nullptr); dir != nullptr)
|
2008-04-05 20:12:11 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
auto ret = std::string{ dir };
|
|
|
|
tr_free(dir);
|
|
|
|
return ret;
|
2022-04-05 01:37:12 +00:00
|
|
|
}
|
2006-10-13 06:29:26 +00:00
|
|
|
|
2014-07-04 00:00:07 +00:00
|
|
|
#ifdef _WIN32
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
if (auto dir = win32_get_known_folder(FOLDERID_Profile); !std::empty(dir))
|
2022-04-05 01:37:12 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
return dir;
|
2022-04-05 01:37:12 +00:00
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2007-08-02 19:43:29 +00:00
|
|
|
#else
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
struct passwd pwent;
|
|
|
|
struct passwd* pw = nullptr;
|
|
|
|
char buf[4096];
|
|
|
|
getpwuid_r(getuid(), &pwent, buf, sizeof buf, &pw);
|
|
|
|
if (pw != nullptr)
|
2022-04-05 01:37:12 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
return pw->pw_dir;
|
2022-04-05 01:37:12 +00:00
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2007-08-02 19:43:29 +00:00
|
|
|
#endif
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
return {};
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2022-07-21 18:22:38 +00:00
|
|
|
static std::string xdgConfigHome()
|
|
|
|
{
|
|
|
|
if (auto* const dir = tr_env_get_string("XDG_CONFIG_HOME", nullptr); dir != nullptr)
|
|
|
|
{
|
|
|
|
auto ret = std::string{ dir };
|
|
|
|
tr_free(dir);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-07-22 18:07:23 +00:00
|
|
|
return fmt::format("{:s}/.config"sv, getHomeDir());
|
2022-07-21 18:22:38 +00:00
|
|
|
}
|
|
|
|
|
2022-07-22 05:52:48 +00:00
|
|
|
void tr_setConfigDir(tr_session* session, std::string_view config_dir)
|
|
|
|
{
|
|
|
|
#if defined(__APPLE__) || defined(_WIN32)
|
|
|
|
auto constexpr ResumeSubdir = "Resume"sv;
|
|
|
|
auto constexpr TorrentSubdir = "Torrents"sv;
|
|
|
|
#else
|
|
|
|
auto constexpr ResumeSubdir = "resume"sv;
|
|
|
|
auto constexpr TorrentSubdir = "torrents"sv;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
session->config_dir = config_dir;
|
2022-07-22 18:07:23 +00:00
|
|
|
session->resume_dir = fmt::format("{:s}/{:s}"sv, config_dir, ResumeSubdir);
|
|
|
|
session->torrent_dir = fmt::format("{:s}/{:s}"sv, config_dir, TorrentSubdir);
|
2022-07-22 05:52:48 +00:00
|
|
|
tr_sys_dir_create(session->resume_dir, TR_SYS_DIR_CREATE_PARENTS, 0777);
|
|
|
|
tr_sys_dir_create(session->torrent_dir, TR_SYS_DIR_CREATE_PARENTS, 0777);
|
|
|
|
}
|
|
|
|
|
|
|
|
char const* tr_sessionGetConfigDir(tr_session const* session)
|
|
|
|
{
|
|
|
|
return session->config_dir.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
char const* tr_getTorrentDir(tr_session const* session)
|
|
|
|
{
|
|
|
|
return session->torrent_dir.c_str();
|
|
|
|
}
|
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
char* tr_getDefaultConfigDir(char const* appname)
|
2008-04-05 20:12:11 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
if (auto* dir = tr_env_get_string("TRANSMISSION_HOME", nullptr); dir != nullptr)
|
|
|
|
{
|
|
|
|
return dir;
|
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2019-07-13 08:52:44 +00:00
|
|
|
if (tr_str_is_empty(appname))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
appname = "Transmission";
|
|
|
|
}
|
2008-12-13 23:17:36 +00:00
|
|
|
|
2014-07-03 19:20:12 +00:00
|
|
|
#ifdef __APPLE__
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
return tr_strvDup(fmt::format("{:s}/Library/Application Support/{:s}"sv, getHomeDir(), appname));
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
#elif defined(_WIN32)
|
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
auto const appdata = win32_get_known_folder(FOLDERID_LocalAppData);
|
|
|
|
return tr_strvDup(fmt::format("{:s}/{:s}"sv, appdata, appname));
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
#elif defined(__HAIKU__)
|
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
char buf[PATH_MAX];
|
|
|
|
find_directory(B_USER_SETTINGS_DIRECTORY, -1, true, buf, sizeof(buf));
|
|
|
|
return tr_strvDup(fmt::format("{:s}/{:s}"sv, buf, appname);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2006-07-16 19:39:23 +00:00
|
|
|
#else
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
return tr_strvDup(fmt::format("{:s}/{:s}"sv, xdgConfigHome(), appname));
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2006-07-16 19:39:23 +00:00
|
|
|
#endif
|
|
|
|
}
|
2008-02-28 19:06:23 +00:00
|
|
|
|
2021-12-16 22:58:58 +00:00
|
|
|
static std::string getXdgEntryFromUserDirs(std::string_view key)
|
|
|
|
{
|
|
|
|
auto content = std::vector<char>{};
|
2022-07-22 18:07:23 +00:00
|
|
|
auto const filename = fmt::format("{:s}/{:s}"sv, xdgConfigHome(), "user-dirs.dirs"sv);
|
2022-07-21 18:22:38 +00:00
|
|
|
if (!tr_sys_path_exists(filename) || !tr_loadFile(filename, content) || std::empty(content))
|
2009-04-05 13:41:38 +00:00
|
|
|
{
|
2021-12-16 22:58:58 +00:00
|
|
|
return {};
|
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-12-16 22:58:58 +00:00
|
|
|
// search for key="val" and extract val
|
2022-04-07 22:26:59 +00:00
|
|
|
auto const search = fmt::format(FMT_STRING("{:s}=\""), key);
|
2021-12-16 22:58:58 +00:00
|
|
|
auto begin = std::search(std::begin(content), std::end(content), std::begin(search), std::end(search));
|
|
|
|
if (begin == std::end(content))
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
std::advance(begin, std::size(search));
|
|
|
|
auto const end = std::find(begin, std::end(content), '"');
|
|
|
|
if (end == std::end(content))
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
auto val = std::string{ begin, end };
|
|
|
|
|
|
|
|
// if val contains "$HOME", replace that with getHomeDir()
|
|
|
|
auto constexpr Home = "$HOME"sv;
|
2022-02-08 05:44:31 +00:00
|
|
|
if (auto const it = std::search(std::begin(val), std::end(val), std::begin(Home), std::end(Home)); it != std::end(val))
|
2021-12-16 22:58:58 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
val.replace(it, it + std::size(Home), getHomeDir());
|
2021-12-16 22:58:58 +00:00
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-12-16 22:58:58 +00:00
|
|
|
return val;
|
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
char* tr_getDefaultDownloadDir()
|
2021-12-16 22:58:58 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
if (auto const dir = getXdgEntryFromUserDirs("XDG_DOWNLOAD_DIR"sv); !std::empty(dir))
|
2021-12-16 22:58:58 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
return tr_strvDup(dir);
|
|
|
|
}
|
2009-04-05 13:33:32 +00:00
|
|
|
|
2015-04-10 22:15:41 +00:00
|
|
|
#ifdef _WIN32
|
2022-07-23 01:10:02 +00:00
|
|
|
if (auto dir = win32_get_known_folder(FOLDERID_Downloads); !std::empty(dir))
|
|
|
|
{
|
|
|
|
return tr_strvDup(dir);
|
|
|
|
}
|
2015-04-10 22:15:41 +00:00
|
|
|
#endif
|
|
|
|
|
2009-07-09 18:18:14 +00:00
|
|
|
#ifdef __HAIKU__
|
2022-07-23 01:10:02 +00:00
|
|
|
return tr_strvDup(fmt::format("{:s}/Desktop"sv, getHomeDir()));
|
2009-07-09 18:18:14 +00:00
|
|
|
#endif
|
2009-04-05 13:33:32 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
return tr_strvDup(fmt::format("{:s}/Downloads"sv, getHomeDir()));
|
2008-11-15 17:39:54 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 04:07:14 +00:00
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
2022-07-22 05:52:48 +00:00
|
|
|
static bool isWebClientDir(std::string_view path)
|
2012-12-05 17:29:46 +00:00
|
|
|
{
|
2022-04-05 01:37:12 +00:00
|
|
|
auto const filename = tr_pathbuf{ path, '/', "index.html"sv };
|
|
|
|
bool const found = tr_sys_path_exists(filename);
|
|
|
|
tr_logAddTrace(fmt::format(FMT_STRING("Searching for web interface file '{:s}'"), filename));
|
|
|
|
return found;
|
2008-07-11 04:07:14 +00:00
|
|
|
}
|
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
std::string tr_getWebClientDir([[maybe_unused]] tr_session const* session)
|
2022-07-22 05:52:48 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
if (auto* const dir = tr_env_get_string("CLUTCH_HOME", nullptr); dir != nullptr)
|
2022-07-22 05:52:48 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
auto ret = std::string{ dir };
|
|
|
|
tr_free(dir);
|
|
|
|
return ret;
|
2022-07-22 05:52:48 +00:00
|
|
|
}
|
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
if (auto* const dir = tr_env_get_string("TRANSMISSION_WEB_HOME", nullptr); dir != nullptr)
|
2022-07-22 05:52:48 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
auto ret = std::string{ dir };
|
|
|
|
tr_free(dir);
|
|
|
|
return ret;
|
2022-07-22 05:52:48 +00:00
|
|
|
}
|
2022-04-05 01:37:12 +00:00
|
|
|
|
|
|
|
#ifdef BUILD_MAC_CLIENT
|
|
|
|
|
|
|
|
// look in the Application Support folder
|
2022-07-23 01:10:02 +00:00
|
|
|
if (auto path = tr_pathbuf{ session->config_dir, "/public_html"sv }; isWebClientDir(path))
|
2022-04-05 01:37:12 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
return std::string{ path };
|
2022-04-05 01:37:12 +00:00
|
|
|
}
|
2008-10-19 17:43:04 +00:00
|
|
|
|
2022-04-05 01:37:12 +00:00
|
|
|
// look in the resource bundle
|
2022-07-23 01:10:02 +00:00
|
|
|
auto app_url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
|
|
|
|
auto app_ref = CFURLCopyFileSystemPath(app_url, kCFURLPOSIXPathStyle);
|
|
|
|
auto const buflen = CFStringGetMaximumSizeOfFileSystemRepresentation(app_ref);
|
|
|
|
auto buf = std::vector<char>(buflen, '\0');
|
|
|
|
bool const success = CFStringGetFileSystemRepresentation(app_ref, std::data(buf), std::size(buf));
|
|
|
|
TR_ASSERT(success);
|
|
|
|
CFRelease(app_url);
|
|
|
|
CFRelease(app_ref);
|
|
|
|
if (auto const path = tr_pathbuf{ std::string_view{ std::data(buf) }, "/Contents/Resources/public_html"sv };
|
|
|
|
isWebClientDir(path))
|
2022-04-05 01:37:12 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
return std::string{ path };
|
2022-04-05 01:37:12 +00:00
|
|
|
}
|
2011-08-15 00:10:06 +00:00
|
|
|
|
2022-04-05 01:37:12 +00:00
|
|
|
#elif defined(_WIN32)
|
2010-03-24 23:41:08 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
/* Generally, Web interface should be stored in a Web subdir of
|
|
|
|
* calling executable dir. */
|
2008-10-19 17:43:04 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
static auto constexpr KnownFolderIds = std::array<KNOWNFOLDERID const* const, 3>{
|
|
|
|
&FOLDERID_LocalAppData,
|
|
|
|
&FOLDERID_RoamingAppData,
|
|
|
|
&FOLDERID_ProgramData,
|
|
|
|
};
|
2022-07-22 05:52:48 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
for (auto const* const folder_id : KnownFolderIds)
|
|
|
|
{
|
|
|
|
auto const dir = win32_get_known_folder(*folder_id);
|
2022-07-22 05:52:48 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
if (auto const path = tr_pathbuf{ dir, "/Transmission/Web"sv }; isWebClientDir(path))
|
|
|
|
{
|
|
|
|
return std::string{ path };
|
2022-04-05 01:37:12 +00:00
|
|
|
}
|
|
|
|
}
|
2008-10-19 17:43:04 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
/* check calling module place */
|
|
|
|
wchar_t wide_module_path[MAX_PATH];
|
|
|
|
GetModuleFileNameW(nullptr, wide_module_path, TR_N_ELEMENTS(wide_module_path));
|
|
|
|
char* module_path = tr_win32_native_to_utf8(wide_module_path, -1);
|
|
|
|
if (auto const dir = tr_sys_path_dirname(module_path); !std::empty(dir))
|
2022-07-21 22:02:13 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
if (auto const path = tr_pathbuf{ dir, "/Web"sv }; isWebClientDir(path))
|
2022-04-05 01:37:12 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
tr_free(module_path);
|
|
|
|
return std::string{ path };
|
2022-04-05 01:37:12 +00:00
|
|
|
}
|
2022-07-22 05:52:48 +00:00
|
|
|
}
|
2022-07-23 01:10:02 +00:00
|
|
|
tr_free(module_path);
|
2008-10-19 17:43:04 +00:00
|
|
|
|
2022-07-22 05:52:48 +00:00
|
|
|
#else // everyone else, follow the XDG spec
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
auto candidates = std::list<std::string>{};
|
2022-07-22 05:52:48 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
/* XDG_DATA_HOME should be the first in the list of candidates */
|
|
|
|
char* tmp = tr_env_get_string("XDG_DATA_HOME", nullptr);
|
|
|
|
if (!tr_str_is_empty(tmp))
|
|
|
|
{
|
|
|
|
candidates.emplace_back(tmp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
candidates.emplace_back(fmt::format("{:s}/.local/share"sv, getHomeDir()));
|
|
|
|
}
|
|
|
|
tr_free(tmp);
|
2008-07-11 04:07:14 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
/* XDG_DATA_DIRS are the backup directories */
|
|
|
|
{
|
|
|
|
char const* const pkg = PACKAGE_DATA_DIR;
|
|
|
|
auto* xdg = tr_env_get_string("XDG_DATA_DIRS", "");
|
|
|
|
auto const buf = fmt::format(FMT_STRING("{:s}:{:s}:/usr/local/share:/usr/share"), pkg, xdg);
|
|
|
|
tr_free(xdg);
|
|
|
|
|
|
|
|
auto sv = std::string_view{ buf };
|
|
|
|
auto token = std::string_view{};
|
|
|
|
while (tr_strvSep(&sv, &token, ':'))
|
2022-04-05 01:37:12 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
token = tr_strvStrip(token);
|
|
|
|
if (!std::empty(token))
|
2022-07-22 05:52:48 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
candidates.emplace_back(token);
|
2022-07-22 05:52:48 +00:00
|
|
|
}
|
2022-04-05 01:37:12 +00:00
|
|
|
}
|
2022-07-23 01:10:02 +00:00
|
|
|
}
|
2012-12-05 17:29:46 +00:00
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
/* walk through the candidates & look for a match */
|
|
|
|
for (auto const& dir : candidates)
|
|
|
|
{
|
|
|
|
if (auto const path = tr_pathbuf{ dir, "/transmission/public_html"sv }; isWebClientDir(path))
|
2022-04-05 01:37:12 +00:00
|
|
|
{
|
2022-07-23 01:10:02 +00:00
|
|
|
return std::string{ path };
|
2008-07-11 04:07:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-05 01:37:12 +00:00
|
|
|
#endif
|
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
return {};
|
2008-07-11 04:07:14 +00:00
|
|
|
}
|
2016-09-21 20:56:03 +00:00
|
|
|
|
2021-11-13 00:10:04 +00:00
|
|
|
std::string tr_getSessionIdDir()
|
2016-09-21 20:56:03 +00:00
|
|
|
{
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
2021-11-13 00:10:04 +00:00
|
|
|
return std::string{ "/tmp"sv };
|
2016-09-21 20:56:03 +00:00
|
|
|
|
|
|
|
#else
|
|
|
|
|
2022-07-23 01:10:02 +00:00
|
|
|
auto const program_data_dir = win32_get_known_folder_ex(FOLDERID_ProgramData, KF_FLAG_CREATE);
|
2022-07-22 18:07:23 +00:00
|
|
|
auto result = fmt::format("{:s}/Transmission"sv, program_data_dir);
|
2022-05-22 01:17:00 +00:00
|
|
|
tr_sys_dir_create(result, 0, 0);
|
2017-04-19 12:04:45 +00:00
|
|
|
return result;
|
2016-09-21 20:56:03 +00:00
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|