diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 39f78bce50e..c2273ef527e 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -440,6 +440,8 @@ namespace BitTorrent virtual qsizetype torrentsCount() const = 0; virtual const SessionStatus &status() const = 0; virtual const CacheStatus &cacheStatus() const = 0; + virtual QString lastExternalIPv6Address() const = 0; + virtual QString lastExternalIPv4Address() const = 0; virtual bool isListening() const = 0; virtual MaxRatioAction maxRatioAction() const = 0; diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index 8de83fdaf56..15cb605fd73 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -4795,6 +4795,16 @@ void SessionImpl::setTrackerFilteringEnabled(const bool enabled) } } +QString SessionImpl::getLastExternalIPv6Address() const +{ + return m_lastExternalIPv6Address; +} + +QString SessionImpl::getLastExternalIPv4Address() const +{ + return m_lastExternalIPv4Address; +} + bool SessionImpl::isListening() const { return m_nativeSessionExtension->isSessionListening(); @@ -5793,15 +5803,27 @@ void SessionImpl::handleListenFailedAlert(const lt::listen_failed_alert *p) void SessionImpl::handleExternalIPAlert(const lt::external_ip_alert *p) { - const QString externalIP {toString(p->external_address)}; + QString externalIP {toString(p->external_address)}; LogMsg(tr("Detected external IP. IP: \"%1\"") .arg(externalIP), Log::INFO); - if (m_lastExternalIP != externalIP) + if (externalIP.indexOf(u':') >= 0) { - if (isReannounceWhenAddressChangedEnabled() && !m_lastExternalIP.isEmpty()) - reannounceToAllTrackers(); - m_lastExternalIP = externalIP; + if (m_lastExternalIPv6Address != externalIP) + { + if (isReannounceWhenAddressChangedEnabled() && !m_lastExternalIPv6Address.isEmpty()) + reannounceToAllTrackers(); + m_lastExternalIPv6Address = externalIP; + } + } + else + { + if (m_lastExternalIPv4Address != externalIP) + { + if (isReannounceWhenAddressChangedEnabled() && !m_lastExternalIPv4Address.isEmpty()) + reannounceToAllTrackers(); + m_lastExternalIPv4Address = externalIP; + } } } diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h index 983427fc2d8..22b4fc194f4 100644 --- a/src/base/bittorrent/sessionimpl.h +++ b/src/base/bittorrent/sessionimpl.h @@ -425,6 +425,9 @@ namespace BitTorrent void topTorrentsQueuePos(const QVector &ids) override; void bottomTorrentsQueuePos(const QVector &ids) override; + QString getLastExternalIPv6Address() const override; + QString getLastExternalIPv4Address() const override; + // Torrent interface void handleTorrentNeedSaveResumeData(const TorrentImpl *torrent); void handleTorrentSaveResumeDataRequested(const TorrentImpl *torrent); @@ -773,7 +776,8 @@ namespace BitTorrent QList m_moveStorageQueue; - QString m_lastExternalIP; + QString m_lastExternalIPv6Address; + QString m_lastExternalIPv4Address; bool m_needUpgradeDownloadPath = false; diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index e69f6fca40f..388ccc16e00 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -1360,6 +1360,7 @@ void MainWindow::showStatusBar(bool show) { // Create status bar m_statusBar = new StatusBar; + connect(m_statusBar.data(), &StatusBar::showExternalAddressesButtonClicked, this, &MainWindow::showExternalAddressesInLog); connect(m_statusBar.data(), &StatusBar::connectionButtonClicked, this, &MainWindow::showConnectionSettings); connect(m_statusBar.data(), &StatusBar::alternativeSpeedsButtonClicked, this, &MainWindow::toggleAlternativeSpeeds); setStatusBar(m_statusBar); @@ -1760,6 +1761,12 @@ void MainWindow::on_actionDonateMoney_triggered() QDesktopServices::openUrl(QUrl(u"https://www.qbittorrent.org/donate"_s)); } +void MainWindow::showExternalAddressesInLog() +{ + displayExecutionLogTab(); + on_actionInformationMessages_triggered(true); +} + void MainWindow::showConnectionSettings() { on_actionOptions_triggered(); diff --git a/src/gui/mainwindow.h b/src/gui/mainwindow.h index 65d1088c8bf..446c65a4d75 100644 --- a/src/gui/mainwindow.h +++ b/src/gui/mainwindow.h @@ -118,6 +118,7 @@ private slots: bool unlockUI(); void notifyOfUpdate(const QString &); void showConnectionSettings(); + void showExternalAddressesInLog(); void minimizeWindow(); // Keyboard shortcuts void createKeyboardShortcuts(); diff --git a/src/gui/statusbar.cpp b/src/gui/statusbar.cpp index 8eef15e7baf..15f5aabcddc 100644 --- a/src/gui/statusbar.cpp +++ b/src/gui/statusbar.cpp @@ -86,6 +86,15 @@ StatusBar::StatusBar(QWidget *parent) m_upSpeedLbl->setStyleSheet(u"text-align:left;"_s); m_upSpeedLbl->setMinimumWidth(200); + m_lastExternalAddressesLbl = new QPushButton(this); + m_lastExternalAddressesLbl->setText(tr("External Address(es): Detecting")); + m_lastExternalAddressesLbl->setIcon(UIThemeManager::instance()->getIcon(u"help-about"_s)); + m_lastExternalAddressesLbl->setFlat(true); + m_lastExternalAddressesLbl->setFocusPolicy(Qt::NoFocus); + m_lastExternalAddressesLbl->setCursor(Qt::PointingHandCursor); + m_lastExternalAddressesLbl->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + connect(m_lastExternalAddressesLbl, &QAbstractButton::clicked, this, &StatusBar::showExternalAddressesButtonClicked); + m_DHTLbl = new QLabel(tr("DHT: %1 nodes").arg(0), this); m_DHTLbl->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); @@ -129,14 +138,21 @@ StatusBar::StatusBar(QWidget *parent) #ifndef Q_OS_MACOS statusSep4->setFrameShadow(QFrame::Raised); #endif - layout->addWidget(m_DHTLbl); + QFrame *statusSep5 = new QFrame(this); + statusSep5->setFrameStyle(QFrame::VLine); +#ifndef Q_OS_MACOS + statusSep5->setFrameShadow(QFrame::Raised); +#endif + layout->addWidget(m_lastExternalAddressesLbl); layout->addWidget(statusSep1); - layout->addWidget(m_connecStatusLblIcon); + layout->addWidget(m_DHTLbl); layout->addWidget(statusSep2); + layout->addWidget(m_connecStatusLblIcon); + layout->addWidget(statusSep3); layout->addWidget(m_altSpeedsBtn); layout->addWidget(statusSep4); layout->addWidget(m_dlSpeedLbl); - layout->addWidget(statusSep3); + layout->addWidget(statusSep5); layout->addWidget(m_upSpeedLbl); addPermanentWidget(container); @@ -212,6 +228,31 @@ void StatusBar::updateDHTNodesNumber() } } +void StatusBar::updateExternalAddressesLabel() +{ + const QString lastExternalIPv4Address = BitTorrent::Session::instance()->getLastExternalIPv4Address(); + const QString lastExternalIPv6Address = BitTorrent::Session::instance()->getLastExternalIPv6Address(); + QString addressText = tr("External Address(es): Detecting"); + + if (!lastExternalIPv4Address.isEmpty() || !lastExternalIPv6Address.isEmpty()) + { + if (!lastExternalIPv4Address.isEmpty() && !lastExternalIPv6Address.isEmpty()) + { + addressText = tr("External Addresses: %1, %2") + .arg(BitTorrent::Session::instance()->getLastExternalIPv4Address()) + .arg(BitTorrent::Session::instance()->getLastExternalIPv6Address()); + } + else + { + addressText = tr("External Address: %1%2") + .arg(BitTorrent::Session::instance()->getLastExternalIPv4Address()) + .arg(BitTorrent::Session::instance()->getLastExternalIPv6Address()); + } + } + + m_lastExternalAddressesLbl->setText(addressText); +} + void StatusBar::updateSpeedLabels() { const BitTorrent::SessionStatus &sessionStatus = BitTorrent::Session::instance()->status(); @@ -235,6 +276,7 @@ void StatusBar::refresh() { updateConnectionStatus(); updateDHTNodesNumber(); + updateExternalAddressesLabel(); updateSpeedLabels(); } diff --git a/src/gui/statusbar.h b/src/gui/statusbar.h index be5f993d08c..d7f29a1cd64 100644 --- a/src/gui/statusbar.h +++ b/src/gui/statusbar.h @@ -50,6 +50,7 @@ class StatusBar final : public QStatusBar signals: void alternativeSpeedsButtonClicked(); void connectionButtonClicked(); + void showExternalAddressesButtonClicked(); public slots: void showRestartRequired(); @@ -62,10 +63,12 @@ private slots: private: void updateConnectionStatus(); void updateDHTNodesNumber(); + void updateExternalAddressesLabel(); void updateSpeedLabels(); QPushButton *m_dlSpeedLbl = nullptr; QPushButton *m_upSpeedLbl = nullptr; + QPushButton *m_lastExternalAddressesLbl = nullptr; QLabel *m_DHTLbl = nullptr; QPushButton *m_connecStatusLblIcon = nullptr; QPushButton *m_altSpeedsBtn = nullptr; diff --git a/src/webui/api/synccontroller.cpp b/src/webui/api/synccontroller.cpp index cb26a38fb51..b52c7209f4c 100644 --- a/src/webui/api/synccontroller.cpp +++ b/src/webui/api/synccontroller.cpp @@ -82,6 +82,8 @@ namespace // TransferInfo keys const QString KEY_TRANSFER_CONNECTION_STATUS = u"connection_status"_s; + const QString KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V6 = u"last_external_address_v6"_s; + const QString KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V4 = u"last_external_address_v4"_s; const QString KEY_TRANSFER_DHT_NODES = u"dht_nodes"_s; const QString KEY_TRANSFER_DLDATA = u"dl_info_data"_s; const QString KEY_TRANSFER_DLRATELIMIT = u"dl_rate_limit"_s; @@ -161,6 +163,8 @@ namespace map[KEY_TRANSFER_AVERAGE_TIME_QUEUE] = cacheStatus.averageJobTime; map[KEY_TRANSFER_TOTAL_QUEUED_SIZE] = cacheStatus.queuedBytes; + map[KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V6] = session->getLastExternalIPv6Address(); + map[KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V4] = session->getLastExternalIPv4Address(); map[KEY_TRANSFER_DHT_NODES] = sessionStatus.dhtNodes; map[KEY_TRANSFER_CONNECTION_STATUS] = session->isListening() ? (sessionStatus.hasIncomingConnections ? u"connected"_s : u"firewalled"_s) @@ -445,6 +449,8 @@ void SyncController::updateFreeDiskSpace(const qint64 freeDiskSpace) // - "total_size": Size including unwanted data // Server state map may contain the following keys: // - "connection_status": connection status +// - "last_external_address_v6": last external address v6 +// - "last_external_address_v4": last external address v4 // - "dht_nodes": DHT nodes count // - "dl_info_data": bytes downloaded // - "dl_info_speed": download speed diff --git a/src/webui/api/transfercontroller.cpp b/src/webui/api/transfercontroller.cpp index 11580427056..39b029b241c 100644 --- a/src/webui/api/transfercontroller.cpp +++ b/src/webui/api/transfercontroller.cpp @@ -45,6 +45,8 @@ const QString KEY_TRANSFER_DLRATELIMIT = u"dl_rate_limit"_s; const QString KEY_TRANSFER_UPSPEED = u"up_info_speed"_s; const QString KEY_TRANSFER_UPDATA = u"up_info_data"_s; const QString KEY_TRANSFER_UPRATELIMIT = u"up_rate_limit"_s; +const QString KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V6 = u"last_external_address_v6"_s; +const QString KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V4 = u"last_external_address_v4"_s; const QString KEY_TRANSFER_DHT_NODES = u"dht_nodes"_s; const QString KEY_TRANSFER_CONNECTION_STATUS = u"connection_status"_s; @@ -57,6 +59,7 @@ const QString KEY_TRANSFER_CONNECTION_STATUS = u"connection_status"_s; // - "up_info_data": Data uploaded this session // - "dl_rate_limit": Download rate limit // - "up_rate_limit": Upload rate limit +// - "external_address": external address // - "dht_nodes": DHT nodes connected to // - "connection_status": Connection status void TransferController::infoAction() @@ -71,6 +74,8 @@ void TransferController::infoAction() dict[KEY_TRANSFER_UPDATA] = static_cast(sessionStatus.totalPayloadUpload); dict[KEY_TRANSFER_DLRATELIMIT] = BitTorrent::Session::instance()->downloadSpeedLimit(); dict[KEY_TRANSFER_UPRATELIMIT] = BitTorrent::Session::instance()->uploadSpeedLimit(); + dict[KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V6] = BitTorrent::Session::instance()->getLastExternalIPv6Address(); + dict[KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V4] = BitTorrent::Session::instance()->getLastExternalIPv4Address(); dict[KEY_TRANSFER_DHT_NODES] = static_cast(sessionStatus.dhtNodes); if (!BitTorrent::Session::instance()->isListening()) dict[KEY_TRANSFER_CONNECTION_STATUS] = u"disconnected"_s; diff --git a/src/webui/www/private/index.html b/src/webui/www/private/index.html index 768ffac2f40..d83fe7afd1a 100644 --- a/src/webui/www/private/index.html +++ b/src/webui/www/private/index.html @@ -243,6 +243,8 @@

qBittorrent Web User Interface + QBT_TR(Show external addresses in log viewer)QBT_TR[CONTEXT=MainWindow] + QBT_TR(Connection status: Firewalled)QBT_TR[CONTEXT=MainWindow] diff --git a/src/webui/www/private/scripts/client.js b/src/webui/www/private/scripts/client.js index e2e8f279cf7..2c25f59f526 100644 --- a/src/webui/www/private/scripts/client.js +++ b/src/webui/www/private/scripts/client.js @@ -843,6 +843,21 @@ window.addEvent('load', function() { else document.title = ("qBittorrent " + qbtVersion() + " QBT_TR(Web UI)QBT_TR[CONTEXT=OptionsDialog]"); $('freeSpaceOnDisk').set('html', 'QBT_TR(Free space: %1)QBT_TR[CONTEXT=HttpServer]'.replace("%1", window.qBittorrent.Misc.friendlyUnit(serverState.free_space_on_disk))); + + let last_external_address_v4 = serverState.last_external_address_v4; + let last_external_address_v6 = serverState.last_external_address_v6; + let last_external_addresses = 'QBT_TR(External Address(es): Detecting)QBT_TR[CONTEXT=HttpServer]'; + + if (last_external_address_v4 !== "" || last_external_address_v6 !== "") + { + if (last_external_address_v4 !== "" && last_external_address_v6 !== "") + last_external_addresses = 'QBT_TR(External Addresses: %1, %2)QBT_TR[CONTEXT=HttpServer]'; + else + last_external_addresses = 'QBT_TR(External Address: %1%2)QBT_TR[CONTEXT=HttpServer]'; + } + + $('freeSpaceOnDisk').set('html', 'QBT_TR(Free space: %1)QBT_TR[CONTEXT=HttpServer]'.replace("%1", window.qBittorrent.Misc.friendlyUnit(serverState.free_space_on_disk))); + $('externalAddresses').set('html', last_external_addresses.replace("%1", last_external_address_v4).replace("%2", last_external_address_v6)); $('DHTNodes').set('html', 'QBT_TR(DHT: %1 nodes)QBT_TR[CONTEXT=StatusBar]'.replace("%1", serverState.dht_nodes)); // Statistics dialog @@ -1024,6 +1039,17 @@ window.addEvent('load', function() { updateTabDisplay(); }); + $('showExternalAddressesInLogViewerLink').addEvent('click', function(e) { + showLogViewer = true; + LocalPreferences.set('show_log_viewer', showLogViewer.toString()); + updateTabDisplay(); + $("logTabLink").click(); + $("logLevelSelect").options[2].selected = true; + window.qBittorrent.Log.logLevelChanged(); + $("filterTextInput").value = 'QBT_TR(Detected external IP.)QBT_TR[CONTEXT=MainWindow]'; + window.qBittorrent.Log.filterTextChanged(); + }); + const updateTabDisplay = function() { if (showRssReader) { $('showRssReaderLink').firstChild.style.opacity = '1';