From 19d6de795c125846b72c09b987902b3fcfd27d39 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Fri, 28 Dec 2018 12:32:45 +0800 Subject: [PATCH 1/3] Drop support for "BC Link" format The format is marked obsolete on 2009.12.28 and has been replaced by magnet links. http://wiki.bitcomet.com/inside_bitcomet#bc_link_format_obsoleted_as_of_v117 https://www.bitcomet.com/en/changelog --- src/base/bittorrent/magneturi.cpp | 45 +++++++++++++------------------ 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/src/base/bittorrent/magneturi.cpp b/src/base/bittorrent/magneturi.cpp index a1b76bfd5..cd39e5d3f 100644 --- a/src/base/bittorrent/magneturi.cpp +++ b/src/base/bittorrent/magneturi.cpp @@ -31,29 +31,26 @@ #include #include #include +#include -#include #include -#include - -#include "base/utils/string.h" namespace { - QString bcLinkToMagnet(QString bcLink) + bool isBitTorrentInfoHash(const QString &string) { - QByteArray rawBc = bcLink.toUtf8(); - rawBc = rawBc.mid(8); // skip bc://bt/ - rawBc = QByteArray::fromBase64(rawBc); // Decode base64 - // Format is now AA/url_encoded_filename/size_bytes/info_hash/ZZ - QStringList parts = QString(rawBc).split('/'); - if (parts.size() != 5) return QString(); + // There are 2 represenations for BitTorrent info hash: + // 1. 40 chars hex-encoded string + // == 20 (SHA-1 length in bytes) * 2 (each byte maps to 2 hex characters) + // 2. 32 chars Base32 encoded string + // == 20 (SHA-1 length in bytes) * 1.6 (the efficiency of Base32 encoding) + const int SHA1_HEX_SIZE = libtorrent::sha1_hash::size * 2; + const int SHA1_BASE32_SIZE = libtorrent::sha1_hash::size * 1.6; - QString filename = parts.at(1); - QString hash = parts.at(3); - QString magnet = "magnet:?xt=urn:btih:" + hash; - magnet += "&dn=" + filename; - return magnet; + return ((((string.size() == SHA1_HEX_SIZE)) + && !string.contains(QRegularExpression(QLatin1String("[^0-9A-Fa-f]")))) + || ((string.size() == SHA1_BASE32_SIZE) + && !string.contains(QRegularExpression(QLatin1String("[^2-7A-Za-z]"))))); } } @@ -66,17 +63,11 @@ MagnetUri::MagnetUri(const QString &source) { if (source.isEmpty()) return; - if (source.startsWith("bc://bt/", Qt::CaseInsensitive)) { - qDebug("Creating magnet link from bc link"); - m_url = bcLinkToMagnet(source); - } - else if (((source.size() == 40) && !source.contains(QRegularExpression("[^0-9A-Fa-f]"))) - || ((source.size() == 32) && !source.contains(QRegularExpression("[^2-7A-Za-z]")))) { - m_url = "magnet:?xt=urn:btih:" + source; - } + if (isBitTorrentInfoHash(source)) + m_url = QLatin1String("magnet:?xt=urn:btih:") + source; libt::error_code ec; - libt::parse_magnet_uri(m_url.toUtf8().constData(), m_addTorrentParams, ec); + libt::parse_magnet_uri(m_url.toStdString(), m_addTorrentParams, ec); if (ec) return; m_valid = true; @@ -84,10 +75,10 @@ MagnetUri::MagnetUri(const QString &source) m_name = QString::fromStdString(m_addTorrentParams.name); for (const std::string &tracker : m_addTorrentParams.trackers) - m_trackers.append(QString::fromStdString(tracker)); + m_trackers.append(TrackerEntry(tracker)); for (const std::string &urlSeed : m_addTorrentParams.url_seeds) - m_urlSeeds.append(QUrl(urlSeed.c_str())); + m_urlSeeds.append(QUrl(QString::fromStdString(urlSeed))); } bool MagnetUri::isValid() const From 6759446639d6be0f159371390168c27a739919a6 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Fri, 28 Dec 2018 13:38:08 +0800 Subject: [PATCH 2/3] Cleanup code Also remove redundant code, it is already handled correctly in subsequent function calls. --- src/base/bittorrent/session.cpp | 11 ++++++----- src/base/bittorrent/session.h | 2 +- src/gui/addnewtorrentdialog.cpp | 34 ++++++++++++++++----------------- src/gui/addnewtorrentdialog.h | 4 ++-- src/gui/mainwindow.cpp | 7 +------ 5 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index c9e0d442c..fd3278db3 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -2090,12 +2090,9 @@ TorrentStatusReport Session::torrentStatusReport() const return m_torrentStatusReport; } -// source - .torrent file path/url or magnet uri -bool Session::addTorrent(QString source, const AddTorrentParams ¶ms) +bool Session::addTorrent(const QString &source, const AddTorrentParams ¶ms) { - MagnetUri magnetUri(source); - if (magnetUri.isValid()) - return addTorrent_impl(CreateTorrentParams(params), magnetUri); + // `source`: .torrent file path/url or magnet uri if (Utils::Misc::isUrl(source)) { LogMsg(tr("Downloading '%1', please wait...", "e.g: Downloading 'xxx.torrent', please wait...").arg(source)); @@ -2110,6 +2107,10 @@ bool Session::addTorrent(QString source, const AddTorrentParams ¶ms) return true; } + const MagnetUri magnetUri {source}; + if (magnetUri.isValid()) + return addTorrent_impl(CreateTorrentParams(params), magnetUri); + TorrentFileGuard guard(source); if (addTorrent_impl(CreateTorrentParams(params) , MagnetUri(), TorrentInfo::loadFromFile(source))) { diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 3b863b737..873421d26 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -469,7 +469,7 @@ namespace BitTorrent void banIP(const QString &ip); bool isKnownTorrent(const InfoHash &hash) const; - bool addTorrent(QString source, const AddTorrentParams ¶ms = AddTorrentParams()); + bool addTorrent(const QString &source, const AddTorrentParams ¶ms = AddTorrentParams()); bool addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams ¶ms = AddTorrentParams()); bool deleteTorrent(const QString &hash, bool deleteLocalFiles = false); bool loadMetadata(const MagnetUri &magnetUri); diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp index 132207714..784cb953c 100644 --- a/src/gui/addnewtorrentdialog.cpp +++ b/src/gui/addnewtorrentdialog.cpp @@ -227,7 +227,7 @@ void AddNewTorrentDialog::saveState() settings()->storeValue(KEY_EXPANDED, m_ui->toolButtonAdvanced->isChecked()); } -void AddNewTorrentDialog::show(QString source, const BitTorrent::AddTorrentParams &inParams, QWidget *parent) +void AddNewTorrentDialog::show(const QString &source, const BitTorrent::AddTorrentParams &inParams, QWidget *parent) { AddNewTorrentDialog *dlg = new AddNewTorrentDialog(inParams, parent); @@ -240,27 +240,27 @@ void AddNewTorrentDialog::show(QString source, const BitTorrent::AddTorrentParam , dlg, &AddNewTorrentDialog::handleDownloadFinished); connect(handler, &Net::DownloadHandler::downloadFailed, dlg, &AddNewTorrentDialog::handleDownloadFailed); connect(handler, &Net::DownloadHandler::redirectedToMagnet, dlg, &AddNewTorrentDialog::handleRedirectedToMagnet); + return; + } + + const BitTorrent::MagnetUri magnetUri(source); + const bool isLoaded = magnetUri.isValid() + ? dlg->loadMagnet(magnetUri) + : dlg->loadTorrent(source); + + if (isLoaded) { +#ifdef Q_OS_MAC + dlg->exec(); +#else + dlg->open(); +#endif } else { - bool ok = false; - BitTorrent::MagnetUri magnetUri(source); - if (magnetUri.isValid()) - ok = dlg->loadMagnet(magnetUri); - else - ok = dlg->loadTorrent(source); - - if (ok) -#ifdef Q_OS_MAC - dlg->exec(); -#else - dlg->open(); -#endif - else - delete dlg; + delete dlg; } } -void AddNewTorrentDialog::show(QString source, QWidget *parent) +void AddNewTorrentDialog::show(const QString &source, QWidget *parent) { show(source, BitTorrent::AddTorrentParams(), parent); } diff --git a/src/gui/addnewtorrentdialog.h b/src/gui/addnewtorrentdialog.h index e2636dfe1..6a9e80434 100644 --- a/src/gui/addnewtorrentdialog.h +++ b/src/gui/addnewtorrentdialog.h @@ -68,8 +68,8 @@ public: static int savePathHistoryLength(); static void setSavePathHistoryLength(int value); - static void show(QString source, const BitTorrent::AddTorrentParams &inParams, QWidget *parent); - static void show(QString source, QWidget *parent); + static void show(const QString &source, const BitTorrent::AddTorrentParams &inParams, QWidget *parent); + static void show(const QString &source, QWidget *parent); private slots: void showAdvancedSettings(bool show); diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index bf70bc83b..64b03877e 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -1628,11 +1627,7 @@ void MainWindow::showNotificationBaloon(QString title, QString msg) const void MainWindow::downloadFromURLList(const QStringList &urlList) { const bool useTorrentAdditionDialog = AddNewTorrentDialog::isEnabled(); - for (QString url : urlList) { - if (((url.size() == 40) && !url.contains(QRegularExpression("[^0-9A-Fa-f]"))) - || ((url.size() == 32) && !url.contains(QRegularExpression("[^2-7A-Za-z]")))) - url = "magnet:?xt=urn:btih:" + url; - + for (const QString &url : urlList) { if (useTorrentAdditionDialog) AddNewTorrentDialog::show(url, this); else From 2b903fc3d16695d69359c13357f5a73696423e21 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sat, 29 Dec 2018 20:38:51 +0800 Subject: [PATCH 3/3] Move Utils::Misc::isUrl() function All usage of this function gets to call Net::DownloadManager eventually. --- src/base/bittorrent/session.cpp | 2 +- src/base/net/downloadmanager.cpp | 11 +++++++++++ src/base/net/downloadmanager.h | 2 ++ src/base/search/searchpluginmanager.cpp | 3 +-- src/base/utils/misc.cpp | 8 -------- src/base/utils/misc.h | 1 - src/gui/addnewtorrentdialog.cpp | 2 +- src/gui/mainwindow.cpp | 3 ++- src/gui/rss/rsswidget.cpp | 3 +-- src/gui/search/pluginselectdialog.cpp | 3 +-- 10 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index fd3278db3..bd6072eac 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -2094,7 +2094,7 @@ bool Session::addTorrent(const QString &source, const AddTorrentParams ¶ms) { // `source`: .torrent file path/url or magnet uri - if (Utils::Misc::isUrl(source)) { + if (Net::DownloadManager::hasSupportedScheme(source)) { LogMsg(tr("Downloading '%1', please wait...", "e.g: Downloading 'xxx.torrent', please wait...").arg(source)); // Launch downloader Net::DownloadHandler *handler = diff --git a/src/base/net/downloadmanager.cpp b/src/base/net/downloadmanager.cpp index a61e102cd..68a251d57 100644 --- a/src/base/net/downloadmanager.cpp +++ b/src/base/net/downloadmanager.cpp @@ -29,6 +29,8 @@ #include "downloadmanager.h" +#include + #include #include #include @@ -210,6 +212,15 @@ bool Net::DownloadManager::deleteCookie(const QNetworkCookie &cookie) return static_cast(m_networkManager.cookieJar())->deleteCookie(cookie); } +bool Net::DownloadManager::hasSupportedScheme(const QString &url) +{ + const QStringList schemes = instance()->m_networkManager.supportedSchemes(); + return std::any_of(schemes.cbegin(), schemes.cend(), [&url](const QString &scheme) + { + return url.startsWith((scheme + QLatin1Char(':')), Qt::CaseInsensitive); + }); +} + void Net::DownloadManager::applyProxySettings() { auto proxyManager = ProxyConfigurationManager::instance(); diff --git a/src/base/net/downloadmanager.h b/src/base/net/downloadmanager.h index 1035ddf27..3aa1a1399 100644 --- a/src/base/net/downloadmanager.h +++ b/src/base/net/downloadmanager.h @@ -103,6 +103,8 @@ namespace Net void setAllCookies(const QList &cookieList); bool deleteCookie(const QNetworkCookie &cookie); + static bool hasSupportedScheme(const QString &url); + private slots: #ifndef QT_NO_OPENSSL void ignoreSslErrors(QNetworkReply *, const QList &); diff --git a/src/base/search/searchpluginmanager.cpp b/src/base/search/searchpluginmanager.cpp index fad3cf737..767859326 100644 --- a/src/base/search/searchpluginmanager.cpp +++ b/src/base/search/searchpluginmanager.cpp @@ -50,7 +50,6 @@ #include "base/utils/bytearray.h" #include "base/utils/foreignapps.h" #include "base/utils/fs.h" -#include "base/utils/misc.h" #include "searchdownloadhandler.h" #include "searchhandler.h" @@ -198,7 +197,7 @@ void SearchPluginManager::installPlugin(const QString &source) { clearPythonCache(engineLocation()); - if (Utils::Misc::isUrl(source)) { + if (Net::DownloadManager::hasSupportedScheme(source)) { using namespace Net; DownloadHandler *handler = DownloadManager::instance()->download(DownloadRequest(source).saveToFile(true)); connect(handler, static_cast(&DownloadHandler::downloadFinished) diff --git a/src/base/utils/misc.cpp b/src/base/utils/misc.cpp index 83e43cc8f..cb573ba70 100644 --- a/src/base/utils/misc.cpp +++ b/src/base/utils/misc.cpp @@ -414,14 +414,6 @@ QList Utils::Misc::boolListfromStringList(const QStringList &l) return ret; } -bool Utils::Misc::isUrl(const QString &s) -{ - static const QRegularExpression reURLScheme( - "http[s]?|ftp", QRegularExpression::CaseInsensitiveOption); - - return reURLScheme.match(QUrl(s).scheme()).hasMatch(); -} - QString Utils::Misc::parseHtmlLinks(const QString &rawText) { QString result = rawText; diff --git a/src/base/utils/misc.h b/src/base/utils/misc.h index 390217d25..f1a081b11 100644 --- a/src/base/utils/misc.h +++ b/src/base/utils/misc.h @@ -71,7 +71,6 @@ namespace Utils }; QString parseHtmlLinks(const QString &rawText); - bool isUrl(const QString &s); void shutdownComputer(const ShutdownDialogAction &action); diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp index 784cb953c..5d126ab31 100644 --- a/src/gui/addnewtorrentdialog.cpp +++ b/src/gui/addnewtorrentdialog.cpp @@ -231,7 +231,7 @@ void AddNewTorrentDialog::show(const QString &source, const BitTorrent::AddTorre { AddNewTorrentDialog *dlg = new AddNewTorrentDialog(inParams, parent); - if (Utils::Misc::isUrl(source)) { + if (Net::DownloadManager::hasSupportedScheme(source)) { // Launch downloader // TODO: Don't save loaded torrent to file, just use downloaded data! Net::DownloadHandler *handler = Net::DownloadManager::instance()->download( diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 64b03877e..5bf9f05cb 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -60,6 +60,7 @@ #include "base/bittorrent/torrenthandle.h" #include "base/global.h" #include "base/logger.h" +#include "base/net/downloadmanager.h" #include "base/preferences.h" #include "base/rss/rss_folder.h" #include "base/rss/rss_session.h" @@ -1295,7 +1296,7 @@ void MainWindow::dropEvent(QDropEvent *event) for (const QString &file : asConst(files)) { const bool isTorrentLink = (file.startsWith("magnet:", Qt::CaseInsensitive) || file.endsWith(C_TORRENT_FILE_EXTENSION, Qt::CaseInsensitive) - || Utils::Misc::isUrl(file)); + || Net::DownloadManager::hasSupportedScheme(file)); if (isTorrentLink) torrentFiles << file; else diff --git a/src/gui/rss/rsswidget.cpp b/src/gui/rss/rsswidget.cpp index 77b8eb4f6..b0a0d4a6a 100644 --- a/src/gui/rss/rsswidget.cpp +++ b/src/gui/rss/rsswidget.cpp @@ -48,7 +48,6 @@ #include "base/rss/rss_feed.h" #include "base/rss/rss_folder.h" #include "base/rss/rss_session.h" -#include "base/utils/misc.h" #include "addnewtorrentdialog.h" #include "articlelistwidget.h" #include "autoexpandabledialog.h" @@ -249,7 +248,7 @@ void RSSWidget::on_newFeedButton_clicked() { // Ask for feed URL const QString clipText = qApp->clipboard()->text(); - const QString defaultURL = (Utils::Misc::isUrl(clipText) ? clipText : "http://"); + const QString defaultURL = Net::DownloadManager::hasSupportedScheme(clipText) ? clipText : "http://"; bool ok; QString newURL = AutoExpandableDialog::getText( diff --git a/src/gui/search/pluginselectdialog.cpp b/src/gui/search/pluginselectdialog.cpp index a297927b4..f2bf24c5d 100644 --- a/src/gui/search/pluginselectdialog.cpp +++ b/src/gui/search/pluginselectdialog.cpp @@ -43,7 +43,6 @@ #include "base/net/downloadhandler.h" #include "base/net/downloadmanager.h" #include "base/utils/fs.h" -#include "base/utils/misc.h" #include "autoexpandabledialog.h" #include "guiiconprovider.h" #include "pluginsourcedialog.h" @@ -337,7 +336,7 @@ void PluginSelectDialog::askForPluginUrl() bool ok = false; QString clipTxt = qApp->clipboard()->text(); QString defaultUrl = "http://"; - if (Utils::Misc::isUrl(clipTxt) && clipTxt.endsWith(".py")) + if (Net::DownloadManager::hasSupportedScheme(clipTxt) && clipTxt.endsWith(".py")) defaultUrl = clipTxt; QString url = AutoExpandableDialog::getText( this, tr("New search engine plugin URL"),