Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 34 additions & 8 deletions src/base/bittorrent/sessionimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,8 +552,8 @@ SessionImpl::SessionImpl(QObject *parent)
, m_storedTags(BITTORRENT_SESSION_KEY(u"Tags"_s))
, m_shareLimitAction(BITTORRENT_SESSION_KEY(u"ShareLimitAction"_s), ShareLimitAction::Stop
, [](const ShareLimitAction action) { return (action == ShareLimitAction::Default) ? ShareLimitAction::Stop : action; })
, m_savePath(BITTORRENT_SESSION_KEY(u"DefaultSavePath"_s), specialFolderLocation(SpecialFolder::Downloads))
, m_downloadPath(BITTORRENT_SESSION_KEY(u"TempPath"_s), (savePath() / Path(u"temp"_s)))
, m_savePath(BITTORRENT_SESSION_KEY(u"DefaultSavePath"_s), specialFolderLocation(SpecialFolder::Downloads), Utils::Fs::expandTilde)
, m_downloadPath(BITTORRENT_SESSION_KEY(u"TempPath"_s), (savePath() / Path(u"temp"_s)), Utils::Fs::expandTilde)
, m_isDownloadPathEnabled(BITTORRENT_SESSION_KEY(u"TempPathEnabled"_s), false)
, m_isSubcategoriesEnabled(BITTORRENT_SESSION_KEY(u"SubcategoriesEnabled"_s), false)
, m_useCategoryPathsInManualMode(BITTORRENT_SESSION_KEY(u"UseCategoryPathsInManualMode"_s), false)
Expand Down Expand Up @@ -1006,6 +1006,14 @@ bool SessionImpl::addCategory(const QString &name, const CategoryOptions &option
if (!isValidCategoryName(name) || m_categories.contains(name))
return false;

// Expand tildes in category save path
CategoryOptions expandedOptions = options;
expandedOptions.savePath = Utils::Fs::expandTilde(options.savePath);
if (expandedOptions.downloadPath.has_value())
{
expandedOptions.downloadPath->path = Utils::Fs::expandTilde(expandedOptions.downloadPath->path);
}

if (isSubcategoriesEnabled())
{
for (const QString &parent : asConst(expandCategory(name)))
Expand All @@ -1018,7 +1026,7 @@ bool SessionImpl::addCategory(const QString &name, const CategoryOptions &option
}
}

m_categories[name] = options;
m_categories[name] = expandedOptions;
storeCategories();
emit categoryAdded(name);

Expand All @@ -1031,8 +1039,16 @@ bool SessionImpl::editCategory(const QString &name, const CategoryOptions &optio
if (it == m_categories.end())
return false;

// Expand tildes in category save path
CategoryOptions expandedOptions = options;
expandedOptions.savePath = Utils::Fs::expandTilde(options.savePath);
if (expandedOptions.downloadPath.has_value())
{
expandedOptions.downloadPath->path = Utils::Fs::expandTilde(expandedOptions.downloadPath->path);
}

CategoryOptions &currentOptions = it.value();
if (options == currentOptions)
if (expandedOptions == currentOptions)
return false;

if (isDisableAutoTMMWhenCategorySavePathChanged())
Expand All @@ -1047,7 +1063,7 @@ bool SessionImpl::editCategory(const QString &name, const CategoryOptions &optio
}
}

currentOptions = options;
currentOptions = expandedOptions;
storeCategories();

for (TorrentImpl *const torrent : asConst(m_torrents))
Expand Down Expand Up @@ -3281,7 +3297,8 @@ void SessionImpl::removeTorrentsQueue()

void SessionImpl::setSavePath(const Path &path)
{
const auto newPath = (path.isAbsolute() ? path : (specialFolderLocation(SpecialFolder::Downloads) / path));
const Path expandedPath = Utils::Fs::expandTilde(path);
const auto newPath = (expandedPath.isAbsolute() ? expandedPath : (specialFolderLocation(SpecialFolder::Downloads) / expandedPath));
if (newPath == m_savePath)
return;

Expand Down Expand Up @@ -3321,7 +3338,8 @@ void SessionImpl::setSavePath(const Path &path)

void SessionImpl::setDownloadPath(const Path &path)
{
const Path newPath = (path.isAbsolute() ? path : (savePath() / Path(u"temp"_s) / path));
const Path expandedPath = Utils::Fs::expandTilde(path);
const Path newPath = (expandedPath.isAbsolute() ? expandedPath : (savePath() / Path(u"temp"_s) / expandedPath));
if (newPath == m_downloadPath)
return;

Expand Down Expand Up @@ -5581,7 +5599,15 @@ void SessionImpl::loadCategories()
for (auto it = jsonObj.constBegin(); it != jsonObj.constEnd(); ++it)
{
const QString &categoryName = it.key();
const auto categoryOptions = CategoryOptions::fromJSON(it.value().toObject());
auto categoryOptions = CategoryOptions::fromJSON(it.value().toObject());

// Expand tildes in loaded category paths
categoryOptions.savePath = Utils::Fs::expandTilde(categoryOptions.savePath);
if (categoryOptions.downloadPath.has_value())
{
categoryOptions.downloadPath->path = Utils::Fs::expandTilde(categoryOptions.downloadPath->path);
}

m_categories[categoryName] = categoryOptions;
}
}
Expand Down
27 changes: 27 additions & 0 deletions src/base/utils/fs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,33 @@ Path Utils::Fs::tempPath()
return path;
}

Path Utils::Fs::expandTilde(const Path &path)
{
if (path.isEmpty())
return path;

const QString pathStr = path.data();

// Check if path starts with ~ (tilde)
if (pathStr.startsWith(u'~'))
{
if (pathStr.size() == 1)
{
// Just ~ means home directory
return homePath();
}
else if (pathStr.at(1) == u'/')
{
// ~/something means home directory + something
return homePath() / Path(pathStr.sliced(2));
}
// ~username is not supported for simplicity and security
}

// Return original path if no tilde expansion needed
return path;
}

bool Utils::Fs::isRegularFile(const Path &path)
{
std::error_code ec;
Expand Down
1 change: 1 addition & 0 deletions src/base/utils/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,5 @@ namespace Utils::Fs

Path homePath();
Path tempPath();
Path expandTilde(const Path &path);
}
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ set(testFiles
testglobal.cpp
testorderedset.cpp
testpath.cpp
testtildeexpansion.cpp
testutilsbytearray.cpp
testutilscompare.cpp
testutilsdatetime.cpp
Expand Down
45 changes: 45 additions & 0 deletions test/testtildeexpansion.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include <QDir>
#include <QObject>
#include <QString>
#include <QTest>

#include "base/path.h"
#include "base/utils/fs.h"

class TestTildeExpansion : public QObject
{
Q_OBJECT

private slots:
void testExpandTilde_data();
void testExpandTilde();
};

void TestTildeExpansion::testExpandTilde_data()
{
QTest::addColumn<QString>("input");
QTest::addColumn<QString>("expected");

const QString homeDir = QDir::homePath();

QTest::newRow("tilde only") << u"~"_s << homeDir;
QTest::newRow("tilde with path") << u"~/Downloads"_s << (homeDir + u"/Downloads"_s);
QTest::newRow("tilde with nested path") << u"~/Documents/qBittorrent"_s << (homeDir + u"/Documents/qBittorrent"_s);
QTest::newRow("absolute path") << u"/absolute/path"_s << u"/absolute/path"_s;
QTest::newRow("relative path") << u"relative/path"_s << u"relative/path"_s;
QTest::newRow("empty path") << u""_s << u""_s;
}

void TestTildeExpansion::testExpandTilde()
{
QFETCH(QString, input);
QFETCH(QString, expected);

const Path inputPath(input);
const Path expandedPath = Utils::Fs::expandTilde(inputPath);

QCOMPARE(expandedPath.data(), expected);
}

QTEST_APPLESS_MAIN(TestTildeExpansion)
#include "testtildeexpansion.moc"