Skip to content

Commit

Permalink
Backport changes to v5.0.x branch
Browse files Browse the repository at this point in the history
PR #21679.
  • Loading branch information
glassez authored Oct 24, 2024
2 parents e58b0a6 + 878d829 commit 9104351
Show file tree
Hide file tree
Showing 417 changed files with 5,873 additions and 5,305 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci_windows.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ jobs:
- name: Install Qt
uses: jurplel/install-qt-action@v4
with:
version: "6.7.0"
version: "6.7.3"
archives: qtbase qtsvg qttools
cache: true

Expand Down
11 changes: 1 addition & 10 deletions src/app/main.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2014-2023 Vladimir Golovnev <[email protected]>
* Copyright (C) 2014-2024 Vladimir Golovnev <[email protected]>
* Copyright (C) 2006 Christophe Dumez <[email protected]>
*
* This program is free software; you can redistribute it and/or
Expand Down Expand Up @@ -58,10 +58,6 @@
#include <QSplashScreen>
#include <QTimer>

#ifdef Q_OS_WIN
#include <QOperatingSystemVersion>
#endif

#ifdef QBT_STATIC_QT
#include <QtPlugin>
Q_IMPORT_PLUGIN(QICOPlugin)
Expand Down Expand Up @@ -189,11 +185,6 @@ int main(int argc, char *argv[])
// We must save it here because QApplication constructor may change it
const bool isOneArg = (argc == 2);

#if !defined(DISABLE_GUI) && defined(Q_OS_WIN)
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10)
QApplication::setStyle(u"Fusion"_s);
#endif

// `app` must be declared out of try block to allow display message box in case of exception
std::unique_ptr<Application> app;
try
Expand Down
57 changes: 29 additions & 28 deletions src/base/addtorrentmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,36 @@ void AddTorrentManager::handleAddTorrentFailed(const QString &source, const QStr
emit addTorrentFailed(source, reason);
}

void AddTorrentManager::handleDuplicateTorrent(const QString &source, BitTorrent::Torrent *torrent, const QString &message)
void AddTorrentManager::handleDuplicateTorrent(const QString &source
, const BitTorrent::TorrentDescriptor &torrentDescr, BitTorrent::Torrent *existingTorrent)
{
const bool hasMetadata = torrentDescr.info().has_value();
if (hasMetadata)
{
// Trying to set metadata to existing torrent in case if it has none
existingTorrent->setMetadata(*torrentDescr.info());
}

const bool isPrivate = existingTorrent->isPrivate() || (hasMetadata && torrentDescr.info()->isPrivate());
QString message;
if (!btSession()->isMergeTrackersEnabled())
{
message = tr("Merging of trackers is disabled");
}
else if (isPrivate)
{
message = tr("Trackers cannot be merged because it is a private torrent");
}
else
{
// merge trackers and web seeds
existingTorrent->addTrackers(torrentDescr.trackers());
existingTorrent->addUrlSeeds(torrentDescr.urlSeeds());
message = tr("Trackers are merged from new source");
}

LogMsg(tr("Detected an attempt to add a duplicate torrent. Source: %1. Existing torrent: %2. Result: %3")
.arg(source, torrent->name(), message));
.arg(source, existingTorrent->name(), message));
emit addTorrentFailed(source, message);
}

Expand All @@ -184,32 +210,7 @@ bool AddTorrentManager::processTorrent(const QString &source, const BitTorrent::
if (BitTorrent::Torrent *torrent = btSession()->findTorrent(infoHash))
{
// a duplicate torrent is being added

const bool hasMetadata = torrentDescr.info().has_value();
if (hasMetadata)
{
// Trying to set metadata to existing torrent in case if it has none
torrent->setMetadata(*torrentDescr.info());
}

if (!btSession()->isMergeTrackersEnabled())
{
handleDuplicateTorrent(source, torrent, tr("Merging of trackers is disabled"));
return false;
}

const bool isPrivate = torrent->isPrivate() || (hasMetadata && torrentDescr.info()->isPrivate());
if (isPrivate)
{
handleDuplicateTorrent(source, torrent, tr("Trackers cannot be merged because it is a private torrent"));
return false;
}

// merge trackers and web seeds
torrent->addTrackers(torrentDescr.trackers());
torrent->addUrlSeeds(torrentDescr.urlSeeds());

handleDuplicateTorrent(source, torrent, tr("Trackers are merged from new source"));
handleDuplicateTorrent(source, torrentDescr, torrent);
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion src/base/addtorrentmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class AddTorrentManager : public ApplicationComponent<QObject>
bool addTorrentToSession(const QString &source, const BitTorrent::TorrentDescriptor &torrentDescr
, const BitTorrent::AddTorrentParams &addTorrentParams);
void handleAddTorrentFailed(const QString &source, const QString &reason);
void handleDuplicateTorrent(const QString &source, BitTorrent::Torrent *torrent, const QString &message);
void handleDuplicateTorrent(const QString &source, const BitTorrent::TorrentDescriptor &torrentDescr, BitTorrent::Torrent *existingTorrent);
void setTorrentFileGuard(const QString &source, std::shared_ptr<TorrentFileGuard> torrentFileGuard);
void releaseTorrentFileGuard(const QString &source);

Expand Down
3 changes: 2 additions & 1 deletion src/base/bittorrent/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ namespace BitTorrent
{
Default = 0,
MMap = 1,
Posix = 2
Posix = 2,
SimplePreadPwrite = 3
};
Q_ENUM_NS(DiskIOType)

Expand Down
87 changes: 52 additions & 35 deletions src/base/bittorrent/sessionimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ SessionImpl::SessionImpl(QObject *parent)
, m_I2POutboundQuantity {BITTORRENT_SESSION_KEY(u"I2P/OutboundQuantity"_s), 3}
, m_I2PInboundLength {BITTORRENT_SESSION_KEY(u"I2P/InboundLength"_s), 3}
, m_I2POutboundLength {BITTORRENT_SESSION_KEY(u"I2P/OutboundLength"_s), 3}
, m_torrentContentRemoveOption {BITTORRENT_SESSION_KEY(u"TorrentContentRemoveOption"_s), TorrentContentRemoveOption::MoveToTrash}
, m_torrentContentRemoveOption {BITTORRENT_SESSION_KEY(u"TorrentContentRemoveOption"_s), TorrentContentRemoveOption::Delete}
, m_startPaused {BITTORRENT_SESSION_KEY(u"StartPaused"_s)}
, m_seedingLimitTimer {new QTimer(this)}
, m_resumeDataTimer {new QTimer(this)}
Expand Down Expand Up @@ -1638,6 +1638,13 @@ void SessionImpl::initializeNativeSession()
#ifdef QBT_USES_LIBTORRENT2
// preserve the same behavior as in earlier libtorrent versions
pack.set_bool(lt::settings_pack::enable_set_file_valid_data, true);

// This is a special case. We use MMap disk IO but tweak it to always fallback to pread/pwrite.
if (diskIOType() == DiskIOType::SimplePreadPwrite)
{
pack.set_int(lt::settings_pack::mmap_file_size_cutoff, std::numeric_limits<int>::max());
pack.set_int(lt::settings_pack::disk_write_mode, lt::settings_pack::mmap_write_mode_t::always_pwrite);
}
#endif

lt::session_params sessionParams {std::move(pack), {}};
Expand All @@ -1648,6 +1655,7 @@ void SessionImpl::initializeNativeSession()
sessionParams.disk_io_constructor = customPosixDiskIOConstructor;
break;
case DiskIOType::MMap:
case DiskIOType::SimplePreadPwrite:
sessionParams.disk_io_constructor = customMMapDiskIOConstructor;
break;
default:
Expand Down Expand Up @@ -2807,6 +2815,19 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr
loadTorrentParams.name = contentName;
}

const auto nativeIndexes = torrentInfo.nativeIndexes();

Q_ASSERT(p.file_priorities.empty());
Q_ASSERT(addTorrentParams.filePriorities.isEmpty() || (addTorrentParams.filePriorities.size() == nativeIndexes.size()));
QList<DownloadPriority> filePriorities = addTorrentParams.filePriorities;

// Filename filter should be applied before `findIncompleteFiles()` is called.
if (filePriorities.isEmpty() && isExcludedFileNamesEnabled())
{
// Check file name blacklist when priorities are not explicitly set
applyFilenameFilter(filePaths, filePriorities);
}

if (!loadTorrentParams.hasFinishedStatus)
{
const Path actualDownloadPath = useAutoTMM
Expand All @@ -2815,24 +2836,12 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr
isFindingIncompleteFiles = true;
}

const auto nativeIndexes = torrentInfo.nativeIndexes();
if (!isFindingIncompleteFiles)
{
for (int index = 0; index < filePaths.size(); ++index)
p.renamed_files[nativeIndexes[index]] = filePaths.at(index).toString().toStdString();
}

Q_ASSERT(p.file_priorities.empty());
Q_ASSERT(addTorrentParams.filePriorities.isEmpty() || (addTorrentParams.filePriorities.size() == nativeIndexes.size()));

QList<DownloadPriority> filePriorities = addTorrentParams.filePriorities;

if (filePriorities.isEmpty() && isExcludedFileNamesEnabled())
{
// Check file name blacklist when priorities are not explicitly set
applyFilenameFilter(filePaths, filePriorities);
}

const int internalFilesCount = torrentInfo.nativeInfo()->files().num_files(); // including .pad files
// Use qBittorrent default priority rather than libtorrent's (4)
p.file_priorities = std::vector(internalFilesCount, LT::toNative(DownloadPriority::Normal));
Expand Down Expand Up @@ -5206,6 +5215,9 @@ void SessionImpl::handleMoveTorrentStorageJobFinished(const Path &newPath)
if (torrent)
{
torrent->handleMoveStorageJobFinished(newPath, finishedJob.context, torrentHasOutstandingJob);
// The torrent may become "finished" at the end of the move if it was moved
// from the "incomplete" location after downloading finished.
processPendingFinishedTorrents();
}
else if (!torrentHasOutstandingJob)
{
Expand All @@ -5217,6 +5229,32 @@ void SessionImpl::handleMoveTorrentStorageJobFinished(const Path &newPath)
}
}

void SessionImpl::processPendingFinishedTorrents()
{
if (m_pendingFinishedTorrents.isEmpty())
return;

for (TorrentImpl *torrent : asConst(m_pendingFinishedTorrents))
{
LogMsg(tr("Torrent download finished. Torrent: \"%1\"").arg(torrent->name()));
emit torrentFinished(torrent);

if (const Path exportPath = finishedTorrentExportDirectory(); !exportPath.isEmpty())
exportTorrentFile(torrent, exportPath);

processTorrentShareLimits(torrent);
}

m_pendingFinishedTorrents.clear();

const bool hasUnfinishedTorrents = std::any_of(m_torrents.cbegin(), m_torrents.cend(), [](const TorrentImpl *torrent)
{
return !(torrent->isFinished() || torrent->isStopped() || torrent->isErrored());
});
if (!hasUnfinishedTorrents)
emit allTorrentsFinished();
}

void SessionImpl::storeCategories() const
{
QJsonObject jsonObj;
Expand Down Expand Up @@ -6108,28 +6146,7 @@ void SessionImpl::handleStateUpdateAlert(const lt::state_update_alert *alert)
if (!updatedTorrents.isEmpty())
emit torrentsUpdated(updatedTorrents);

if (!m_pendingFinishedTorrents.isEmpty())
{
for (TorrentImpl *torrent : m_pendingFinishedTorrents)
{
LogMsg(tr("Torrent download finished. Torrent: \"%1\"").arg(torrent->name()));
emit torrentFinished(torrent);

if (const Path exportPath = finishedTorrentExportDirectory(); !exportPath.isEmpty())
exportTorrentFile(torrent, exportPath);

processTorrentShareLimits(torrent);
}

m_pendingFinishedTorrents.clear();

const bool hasUnfinishedTorrents = std::any_of(m_torrents.cbegin(), m_torrents.cend(), [](const TorrentImpl *torrent)
{
return !(torrent->isFinished() || torrent->isStopped() || torrent->isErrored());
});
if (!hasUnfinishedTorrents)
emit allTorrentsFinished();
}
processPendingFinishedTorrents();

if (m_needSaveTorrentsQueue)
saveTorrentsQueue();
Expand Down
1 change: 1 addition & 0 deletions src/base/bittorrent/sessionimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ namespace BitTorrent

void moveTorrentStorage(const MoveStorageJob &job) const;
void handleMoveTorrentStorageJobFinished(const Path &newPath);
void processPendingFinishedTorrents();

void loadCategories();
void storeCategories() const;
Expand Down
2 changes: 1 addition & 1 deletion src/base/bittorrent/torrentimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1819,7 +1819,7 @@ void TorrentImpl::endReceivedMetadataHandling(const Path &savePath, const PathLi
m_filePriorities.append(LT::fromNative(p.file_priorities[LT::toUnderlyingType(nativeIndex)]));
}

m_session->applyFilenameFilter(fileNames, m_filePriorities);
m_session->applyFilenameFilter(m_filePaths, m_filePriorities);
for (int i = 0; i < m_filePriorities.size(); ++i)
p.file_priorities[LT::toUnderlyingType(nativeIndexes[i])] = LT::toNative(m_filePriorities[i]);

Expand Down
13 changes: 13 additions & 0 deletions src/base/preferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,19 @@ void Preferences::setWinStartup(const bool b)
settings.remove(profileID);
}
}

QString Preferences::getStyle() const
{
return value<QString>(u"Appearance/Style"_s);
}

void Preferences::setStyle(const QString &styleName)
{
if (styleName == getStyle())
return;

setValue(u"Appearance/Style"_s, styleName);
}
#endif // Q_OS_WIN

// Downloads
Expand Down
2 changes: 2 additions & 0 deletions src/base/preferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ class Preferences final : public QObject
#ifdef Q_OS_WIN
bool WinStartup() const;
void setWinStartup(bool b);
QString getStyle() const;
void setStyle(const QString &styleName);
#endif

// Downloads
Expand Down
5 changes: 5 additions & 0 deletions src/base/utils/os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,11 @@ Path Utils::OS::windowsSystemPath()
#if defined(Q_OS_MACOS) || defined(Q_OS_WIN)
bool Utils::OS::applyMarkOfTheWeb(const Path &file, const QString &url)
{
// Trying to apply this to a non-existent file is unacceptable,
// as it may unexpectedly create such a file.
if (!file.exists())
return false;

Q_ASSERT(url.isEmpty() || url.startsWith(u"http:") || url.startsWith(u"https:"));

#ifdef Q_OS_MACOS
Expand Down
1 change: 1 addition & 0 deletions src/gui/advancedsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,7 @@ void AdvancedSettings::loadAdvancedSettings()
m_comboBoxDiskIOType.addItem(tr("Default"), QVariant::fromValue(BitTorrent::DiskIOType::Default));
m_comboBoxDiskIOType.addItem(tr("Memory mapped files"), QVariant::fromValue(BitTorrent::DiskIOType::MMap));
m_comboBoxDiskIOType.addItem(tr("POSIX-compliant"), QVariant::fromValue(BitTorrent::DiskIOType::Posix));
m_comboBoxDiskIOType.addItem(tr("Simple pread/pwrite"), QVariant::fromValue(BitTorrent::DiskIOType::SimplePreadPwrite));
m_comboBoxDiskIOType.setCurrentIndex(m_comboBoxDiskIOType.findData(QVariant::fromValue(session->diskIOType())));
addRow(DISK_IO_TYPE, tr("Disk IO type (requires restart)") + u' ' + makeLink(u"https://www.libtorrent.org/single-page-ref.html#default-disk-io-constructor", u"(?)")
, &m_comboBoxDiskIOType);
Expand Down
Loading

0 comments on commit 9104351

Please sign in to comment.