Browse Source

Implement new GeoIPManager class.

adaptive-webui-19844
Vladimir Golovnev (Glassez) 9 years ago
parent
commit
79976fbfce
  1. 32
      configure
  2. 17
      configure.ac
  3. 3
      macxconf.pri
  4. 4
      os2conf.pri
  5. 8
      src/app/application.cpp
  6. 6
      src/core/bittorrent/peerinfo.cpp
  7. 2
      src/core/bittorrent/peerinfo.h
  8. 3
      src/core/bittorrent/private/sessionprivate.h
  9. 3
      src/core/bittorrent/private/torrenthandleprivate.h
  10. 32
      src/core/bittorrent/session.cpp
  11. 7
      src/core/bittorrent/session.h
  12. 16
      src/core/bittorrent/torrenthandle.cpp
  13. 4
      src/core/bittorrent/torrenthandle.h
  14. 4
      src/core/core.pri
  15. 464
      src/core/net/geoipmanager.cpp
  16. 77
      src/core/net/geoipmanager.h
  17. 631
      src/core/net/private/geoipdatabase.cpp
  18. 48
      src/core/net/private/geoipdatabase.h
  19. 12
      src/gui/geoip/README
  20. 19
      src/gui/geoip/geoip.pri
  21. 5
      src/gui/geoip/geoip.qrc
  22. 203
      src/gui/geoip/geoipmanager.cpp
  23. 1
      src/gui/gui.pri
  24. 6
      src/gui/guiiconprovider.cpp
  25. 1
      src/gui/guiiconprovider.h
  26. 10
      src/gui/properties/peerlistwidget.cpp
  27. 7
      unixconf.pri
  28. 4
      winconf.pri

32
configure vendored

@ -716,7 +716,6 @@ enable_dependency_tracking
enable_silent_rules enable_silent_rules
with_qt5 with_qt5
with_libtorrent_rasterbar0_16 with_libtorrent_rasterbar0_16
with_geoip_database_embedded
with_qtsingleapplication with_qtsingleapplication
with_qjson with_qjson
enable_debug enable_debug
@ -1387,10 +1386,6 @@ Optional Packages:
--with-libtorrent-rasterbar0.16 --with-libtorrent-rasterbar0.16
Compile using libtorrent-rasterbar 0.16.x series Compile using libtorrent-rasterbar 0.16.x series
(default=no) (default=no)
--with-geoip-database-embedded
Embed the GeoIP database in the qBittorrent
executable (please follow instructions in
src/gui/geoip/README) (default=no)
--with-qtsingleapplication=[system|shipped] --with-qtsingleapplication=[system|shipped]
Use the shipped qtsingleapplication library or the Use the shipped qtsingleapplication library or the
system one (default=shipped) system one (default=shipped)
@ -4194,15 +4189,6 @@ fi
# Check whether --with-geoip-database-embedded was given.
if test "${with_geoip_database_embedded+set}" = set; then :
withval=$with_geoip_database_embedded;
else
with_geoip_database_embedded=no
fi
# Check whether --with-qtsingleapplication was given. # Check whether --with-qtsingleapplication was given.
if test "${with_qtsingleapplication+set}" = set; then : if test "${with_qtsingleapplication+set}" = set; then :
withval=$with_qtsingleapplication; withval=$with_qtsingleapplication;
@ -4429,7 +4415,6 @@ $as_echo "yes" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; } $as_echo "no" >&6; }
enable_qt_dbus=no enable_qt_dbus=no
enable_geoip_database=no
QBT_ADD_CONFIG="$QBT_ADD_CONFIG nogui" ;; #( QBT_ADD_CONFIG="$QBT_ADD_CONFIG nogui" ;; #(
*) : *) :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_gui" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_gui" >&5
@ -5493,23 +5478,6 @@ $as_echo "$with_libtorrent_rasterbar0_16" >&6; }
as_fn_error $? "Unknown option \"$with_libtorrent_rasterbar0_16\". Use either \"yes\" or \"no\"." "$LINENO" 5 ;; as_fn_error $? "Unknown option \"$with_libtorrent_rasterbar0_16\". Use either \"yes\" or \"no\"." "$LINENO" 5 ;;
esac esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to embed the GeoIP database" >&5
$as_echo_n "checking whether to embed the GeoIP database... " >&6; }
case "x$with_geoip_database_embedded" in #(
"xno") :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
QBT_REMOVE_DEFINES="$QBT_REMOVE_DEFINES WITH_GEOIP_EMBEDDED" ;; #(
"xyes") :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
QBT_ADD_DEFINES="$QBT_ADD_DEFINES WITH_GEOIP_EMBEDDED" ;; #(
*) :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_geoip_database_embedded" >&5
$as_echo "$with_geoip_database_embedded" >&6; }
as_fn_error $? "Unknown option \"$with_geoip_database_embedded\". Use either \"yes\" or \"no\"." "$LINENO" 5 ;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which qtsingleapplication to use" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking which qtsingleapplication to use" >&5
$as_echo_n "checking which qtsingleapplication to use... " >&6; } $as_echo_n "checking which qtsingleapplication to use... " >&6; }
case "x$with_qtsingleapplication" in #( case "x$with_qtsingleapplication" in #(

17
configure.ac

@ -24,12 +24,6 @@ AC_ARG_WITH(libtorrent-rasterbar0.16,
[], [],
[with_libtorrent_rasterbar0_16=no]) [with_libtorrent_rasterbar0_16=no])
AC_ARG_WITH(geoip-database-embedded,
[AS_HELP_STRING([--with-geoip-database-embedded],
[Embed the GeoIP database in the qBittorrent executable (please follow instructions in src/gui/geoip/README) (default=no)])],
[],
[with_geoip_database_embedded=no])
AC_ARG_WITH(qtsingleapplication, AC_ARG_WITH(qtsingleapplication,
[AS_HELP_STRING([--with-qtsingleapplication=@<:@system|shipped@:>@], [AS_HELP_STRING([--with-qtsingleapplication=@<:@system|shipped@:>@],
[Use the shipped qtsingleapplication library or the system one (default=shipped)])], [Use the shipped qtsingleapplication library or the system one (default=shipped)])],
@ -198,17 +192,6 @@ AS_CASE(["x$with_libtorrent_rasterbar0_16"],
[AC_MSG_RESULT([$with_libtorrent_rasterbar0_16]) [AC_MSG_RESULT([$with_libtorrent_rasterbar0_16])
AC_MSG_ERROR([Unknown option "$with_libtorrent_rasterbar0_16". Use either "yes" or "no".])]) AC_MSG_ERROR([Unknown option "$with_libtorrent_rasterbar0_16". Use either "yes" or "no".])])
AC_MSG_CHECKING([whether to embed the GeoIP database])
AS_CASE(["x$with_geoip_database_embedded"],
["xno"],
[AC_MSG_RESULT([no])
QBT_REMOVE_DEFINES="$QBT_REMOVE_DEFINES WITH_GEOIP_EMBEDDED"],
["xyes"],
[AC_MSG_RESULT([yes])
QBT_ADD_DEFINES="$QBT_ADD_DEFINES WITH_GEOIP_EMBEDDED"],
[AC_MSG_RESULT([$with_geoip_database_embedded])
AC_MSG_ERROR([Unknown option "$with_geoip_database_embedded". Use either "yes" or "no".])])
AC_MSG_CHECKING([which qtsingleapplication to use]) AC_MSG_CHECKING([which qtsingleapplication to use])
AS_CASE(["x$with_qtsingleapplication"], AS_CASE(["x$with_qtsingleapplication"],
["xshipped"], ["xshipped"],

3
macxconf.pri

@ -56,6 +56,3 @@ QMAKE_BUNDLE_DATA += qt_translations
ICON = $$DIST_PATH/qbittorrent_mac.icns ICON = $$DIST_PATH/qbittorrent_mac.icns
QMAKE_INFO_PLIST = $$DIST_PATH/Info.plist QMAKE_INFO_PLIST = $$DIST_PATH/Info.plist
DEFINES += WITH_GEOIP_EMBEDDED
message("On Mac OS X, GeoIP database must be embedded.")

4
os2conf.pri

@ -13,8 +13,4 @@ LIBS += \
RC_FILE = qbittorrent_os2.rc RC_FILE = qbittorrent_os2.rc
# LIBTORRENT DEFINES # LIBTORRENT DEFINES
DEFINES += WITH_SHIPPED_GEOIP_H
DEFINES += BOOST_ASIO_DYN_LINK DEFINES += BOOST_ASIO_DYN_LINK
DEFINES += WITH_GEOIP_EMBEDDED
message("On eCS(OS/2), GeoIP database must be embedded.")

8
src/app/application.cpp

@ -65,6 +65,7 @@
#include "core/scanfoldersmodel.h" #include "core/scanfoldersmodel.h"
#include "core/net/smtp.h" #include "core/net/smtp.h"
#include "core/net/downloadmanager.h" #include "core/net/downloadmanager.h"
#include "core/net/geoipmanager.h"
#include "core/bittorrent/session.h" #include "core/bittorrent/session.h"
#include "core/bittorrent/torrenthandle.h" #include "core/bittorrent/torrenthandle.h"
@ -232,10 +233,14 @@ int Application::exec(const QStringList &params)
#else #else
GuiIconProvider::initInstance(); GuiIconProvider::initInstance();
#endif #endif
BitTorrent::Session::initInstance(); BitTorrent::Session::initInstance();
connect(BitTorrent::Session::instance(), SIGNAL(torrentFinished(BitTorrent::TorrentHandle *const)), SLOT(torrentFinished(BitTorrent::TorrentHandle *const))); connect(BitTorrent::Session::instance(), SIGNAL(torrentFinished(BitTorrent::TorrentHandle *const)), SLOT(torrentFinished(BitTorrent::TorrentHandle *const)));
connect(BitTorrent::Session::instance(), SIGNAL(allTorrentsFinished()), SLOT(allTorrentsFinished())); connect(BitTorrent::Session::instance(), SIGNAL(allTorrentsFinished()), SLOT(allTorrentsFinished()));
#ifndef DISABLE_COUNTRIES_RESOLUTION
Net::GeoIPManager::initInstance();
#endif
ScanFoldersModel::initInstance(this); ScanFoldersModel::initInstance(this);
#ifndef DISABLE_WEBUI #ifndef DISABLE_WEBUI
@ -446,6 +451,9 @@ void Application::cleanup()
ScanFoldersModel::freeInstance(); ScanFoldersModel::freeInstance();
BitTorrent::Session::freeInstance(); BitTorrent::Session::freeInstance();
#ifndef DISABLE_COUNTRIES_RESOLUTION
Net::GeoIPManager::freeInstance();
#endif
Preferences::freeInstance(); Preferences::freeInstance();
Logger::freeInstance(); Logger::freeInstance();
IconProvider::freeInstance(); IconProvider::freeInstance();

6
src/core/bittorrent/peerinfo.cpp

@ -28,6 +28,7 @@
#include <libtorrent/version.hpp> #include <libtorrent/version.hpp>
#include "core/net/geoipmanager.h"
#include "core/utils/string.h" #include "core/utils/string.h"
#include "peerinfo.h" #include "peerinfo.h"
@ -69,11 +70,12 @@ bool PeerInfo::fromLSD() const
return (m_nativeInfo.source & libt::peer_info::lsd); return (m_nativeInfo.source & libt::peer_info::lsd);
} }
#ifndef DISABLE_COUNTRIES_RESOLUTION
QString PeerInfo::country() const QString PeerInfo::country() const
{ {
return QString(QByteArray(m_nativeInfo.country, 2)); return Net::GeoIPManager::instance()->lookup(address().ip);
} }
#endif
bool PeerInfo::isInteresting() const bool PeerInfo::isInteresting() const
{ {

2
src/core/bittorrent/peerinfo.h

@ -89,7 +89,9 @@ namespace BitTorrent
qlonglong totalDownload() const; qlonglong totalDownload() const;
QBitArray pieces() const; QBitArray pieces() const;
QString connectionType() const; QString connectionType() const;
#ifndef DISABLE_COUNTRIES_RESOLUTION
QString country() const; QString country() const;
#endif
private: private:
libtorrent::peer_info m_nativeInfo; libtorrent::peer_info m_nativeInfo;

3
src/core/bittorrent/private/sessionprivate.h

@ -50,9 +50,6 @@ struct SessionPrivate
virtual bool isTempPathEnabled() const = 0; virtual bool isTempPathEnabled() const = 0;
virtual bool isAppendExtensionEnabled() const = 0; virtual bool isAppendExtensionEnabled() const = 0;
virtual bool useAppendLabelToSavePath() const = 0; virtual bool useAppendLabelToSavePath() const = 0;
#ifndef DISABLE_COUNTRIES_RESOLUTION
virtual bool isResolveCountriesEnabled() const = 0;
#endif
virtual QString defaultSavePath() const = 0; virtual QString defaultSavePath() const = 0;
virtual QString tempPath() const = 0; virtual QString tempPath() const = 0;
virtual qreal globalMaxRatio() const = 0; virtual qreal globalMaxRatio() const = 0;

3
src/core/bittorrent/private/torrenthandleprivate.h

@ -42,9 +42,6 @@ struct TorrentHandlePrivate
virtual void handleDefaultSavePathChanged() = 0; virtual void handleDefaultSavePathChanged() = 0;
virtual void handleTempPathChanged() = 0; virtual void handleTempPathChanged() = 0;
virtual void handleAppendExtensionToggled() = 0; virtual void handleAppendExtensionToggled() = 0;
#ifndef DISABLE_COUNTRIES_RESOLUTION
virtual void handleResolveCountriesToggled() = 0;
#endif
protected: protected:
~TorrentHandlePrivate() {} ~TorrentHandlePrivate() {}

32
src/core/bittorrent/session.cpp

@ -63,7 +63,7 @@ using namespace BitTorrent;
//#include <libtorrent/extensions/metadata_transfer.hpp> //#include <libtorrent/extensions/metadata_transfer.hpp>
#ifndef DISABLE_COUNTRIES_RESOLUTION #ifndef DISABLE_COUNTRIES_RESOLUTION
#include "geoipmanager.h" #include "core/net/geoipmanager.h"
#endif #endif
#include "core/utils/misc.h" #include "core/utils/misc.h"
@ -141,10 +141,6 @@ Session::Session(QObject *parent)
, m_globalMaxRatio(-1) , m_globalMaxRatio(-1)
, m_numResumeData(0) , m_numResumeData(0)
, m_extraLimit(0) , m_extraLimit(0)
#ifndef DISABLE_COUNTRIES_RESOLUTION
, m_geoipDBLoaded(false)
, m_resolveCountries(false)
#endif
, m_appendLabelToSavePath(false) , m_appendLabelToSavePath(false)
, m_appendExtension(false) , m_appendExtension(false)
, m_refreshInterval(0) , m_refreshInterval(0)
@ -252,13 +248,6 @@ bool Session::useAppendLabelToSavePath() const
return m_appendLabelToSavePath; return m_appendLabelToSavePath;
} }
#ifndef DISABLE_COUNTRIES_RESOLUTION
bool Session::isResolveCountriesEnabled() const
{
return m_resolveCountries;
}
#endif
QString Session::defaultSavePath() const QString Session::defaultSavePath() const
{ {
return m_defaultSavePath; return m_defaultSavePath;
@ -577,25 +566,6 @@ void Session::configure()
delete m_bwScheduler; delete m_bwScheduler;
} }
#ifndef DISABLE_COUNTRIES_RESOLUTION
// Resolve countries
qDebug("Loading country resolution settings");
const bool new_resolv_countries = pref->resolvePeerCountries();
if (m_resolveCountries != new_resolv_countries) {
qDebug("in country resolution settings");
m_resolveCountries = new_resolv_countries;
if (m_resolveCountries && !m_geoipDBLoaded) {
qDebug("Loading geoip database");
GeoIPManager::loadDatabase(m_nativeSession);
m_geoipDBLoaded = true;
}
// Update torrent handles
foreach (TorrentHandlePrivate *const torrent, m_torrents)
torrent->handleResolveCountriesToggled();
}
#endif
Logger* const logger = Logger::instance(); Logger* const logger = Logger::instance();
// * Session settings // * Session settings

7
src/core/bittorrent/session.h

@ -283,9 +283,6 @@ namespace BitTorrent
bool isTempPathEnabled() const; bool isTempPathEnabled() const;
bool isAppendExtensionEnabled() const; bool isAppendExtensionEnabled() const;
bool useAppendLabelToSavePath() const; bool useAppendLabelToSavePath() const;
#ifndef DISABLE_COUNTRIES_RESOLUTION
bool isResolveCountriesEnabled() const;
#endif
QString defaultSavePath() const; QString defaultSavePath() const;
QString tempPath() const; QString tempPath() const;
void handleTorrentRatioLimitChanged(TorrentHandle *const torrent); void handleTorrentRatioLimitChanged(TorrentHandle *const torrent);
@ -327,10 +324,6 @@ namespace BitTorrent
qreal m_globalMaxRatio; qreal m_globalMaxRatio;
int m_numResumeData; int m_numResumeData;
int m_extraLimit; int m_extraLimit;
#ifndef DISABLE_COUNTRIES_RESOLUTION
bool m_geoipDBLoaded;
bool m_resolveCountries;
#endif
bool m_appendLabelToSavePath; bool m_appendLabelToSavePath;
bool m_appendExtension; bool m_appendExtension;
uint m_refreshInterval; uint m_refreshInterval;

16
src/core/bittorrent/torrenthandle.cpp

@ -205,10 +205,6 @@ TorrentHandle::TorrentHandle(Session *session, const libtorrent::torrent_handle
{ {
initialize(); initialize();
#ifndef DISABLE_COUNTRIES_RESOLUTION
resolveCountries(m_session->isResolveCountriesEnabled());
#endif
if (!data.resumed) { if (!data.resumed) {
setSequentialDownload(data.sequential); setSequentialDownload(data.sequential);
if (hasMetadata()) { if (hasMetadata()) {
@ -1644,13 +1640,6 @@ void TorrentHandle::handleAppendExtensionToggled()
removeExtensionsFromIncompleteFiles(); removeExtensionsFromIncompleteFiles();
} }
#ifndef DISABLE_COUNTRIES_RESOLUTION
void TorrentHandle::handleResolveCountriesToggled()
{
resolveCountries(m_session->isResolveCountriesEnabled());
}
#endif
void TorrentHandle::handleAlert(libtorrent::alert *a) void TorrentHandle::handleAlert(libtorrent::alert *a)
{ {
switch (a->type()) { switch (a->type()) {
@ -1865,11 +1854,6 @@ QString TorrentHandle::toMagnetUri() const
return Utils::String::fromStdString(libt::make_magnet_uri(m_nativeHandle)); return Utils::String::fromStdString(libt::make_magnet_uri(m_nativeHandle));
} }
void TorrentHandle::resolveCountries(bool b)
{
SAFE_CALL(resolve_countries, b);
}
void TorrentHandle::prioritizeFiles(const QVector<int> &priorities) void TorrentHandle::prioritizeFiles(const QVector<int> &priorities)
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;

4
src/core/bittorrent/torrenthandle.h

@ -316,9 +316,6 @@ namespace BitTorrent
void handleDefaultSavePathChanged(); void handleDefaultSavePathChanged();
void handleTempPathChanged(); void handleTempPathChanged();
void handleAppendExtensionToggled(); void handleAppendExtensionToggled();
#ifndef DISABLE_COUNTRIES_RESOLUTION
void handleResolveCountriesToggled();
#endif
void handleStorageMovedAlert(libtorrent::storage_moved_alert *p); void handleStorageMovedAlert(libtorrent::storage_moved_alert *p);
void handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert *p); void handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert *p);
@ -341,7 +338,6 @@ namespace BitTorrent
bool useTempPath() const; bool useTempPath() const;
QString nativeActualSavePath() const; QString nativeActualSavePath() const;
void resolveCountries(bool b);
void adjustSavePath(); void adjustSavePath();
void adjustActualSavePath(); void adjustActualSavePath();
void adjustActualSavePath_impl(); void adjustActualSavePath_impl();

4
src/core/core.pri

@ -16,9 +16,11 @@ HEADERS += \
$$PWD/net/dnsupdater.h \ $$PWD/net/dnsupdater.h \
$$PWD/net/downloadmanager.h \ $$PWD/net/downloadmanager.h \
$$PWD/net/downloadhandler.h \ $$PWD/net/downloadhandler.h \
$$PWD/net/geoipmanager.h \
$$PWD/net/portforwarder.h \ $$PWD/net/portforwarder.h \
$$PWD/net/reverseresolution.h \ $$PWD/net/reverseresolution.h \
$$PWD/net/smtp.h \ $$PWD/net/smtp.h \
$$PWD/net/private/geoipdatabase.h \
$$PWD/bittorrent/infohash.h \ $$PWD/bittorrent/infohash.h \
$$PWD/bittorrent/session.h \ $$PWD/bittorrent/session.h \
$$PWD/bittorrent/sessionstatus.h \ $$PWD/bittorrent/sessionstatus.h \
@ -58,9 +60,11 @@ SOURCES += \
$$PWD/net/dnsupdater.cpp \ $$PWD/net/dnsupdater.cpp \
$$PWD/net/downloadmanager.cpp \ $$PWD/net/downloadmanager.cpp \
$$PWD/net/downloadhandler.cpp \ $$PWD/net/downloadhandler.cpp \
$$PWD/net/geoipmanager.cpp \
$$PWD/net/portforwarder.cpp \ $$PWD/net/portforwarder.cpp \
$$PWD/net/reverseresolution.cpp \ $$PWD/net/reverseresolution.cpp \
$$PWD/net/smtp.cpp \ $$PWD/net/smtp.cpp \
$$PWD/net/private/geoipdatabase.cpp \
$$PWD/bittorrent/infohash.cpp \ $$PWD/bittorrent/infohash.cpp \
$$PWD/bittorrent/session.cpp \ $$PWD/bittorrent/session.cpp \
$$PWD/bittorrent/sessionstatus.cpp \ $$PWD/bittorrent/sessionstatus.cpp \

464
src/core/net/geoipmanager.cpp

@ -0,0 +1,464 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#include <QDebug>
#include <QFile>
#include <QDir>
#include <QHostAddress>
#include <QDateTime>
#include "core/logger.h"
#include "core/preferences.h"
#include "core/utils/fs.h"
#include "core/utils/gzip.h"
#include "downloadmanager.h"
#include "downloadhandler.h"
#include "private/geoipdatabase.h"
#include "geoipmanager.h"
static const char DATABASE_URL[] = "http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz";
static const char GEOIP_FOLDER[] = "GeoIP";
static const char GEOIP_FILENAME[] = "GeoLite2-Country.mmdb";
static const int CACHE_SIZE = 1000;
static const int UPDATE_INTERVAL = 30; // Days between database updates
using namespace Net;
// GeoIPManager
GeoIPManager *GeoIPManager::m_instance = 0;
GeoIPManager::GeoIPManager()
: m_enabled(false)
, m_geoIPDatabase(0)
, m_cache(CACHE_SIZE)
{
configure();
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
}
GeoIPManager::~GeoIPManager()
{
if (m_geoIPDatabase)
delete m_geoIPDatabase;
}
void GeoIPManager::initInstance()
{
if (!m_instance)
m_instance = new GeoIPManager;
}
void GeoIPManager::freeInstance()
{
if (m_instance) {
delete m_instance;
m_instance = 0;
}
}
GeoIPManager *GeoIPManager::instance()
{
return m_instance;
}
void GeoIPManager::loadDatabase()
{
if (m_geoIPDatabase) {
delete m_geoIPDatabase;
m_geoIPDatabase = 0;
}
QString filepath = Utils::Fs::expandPathAbs(
QString("%1%2/%3").arg(Utils::Fs::QDesktopServicesDataLocation())
.arg(GEOIP_FOLDER).arg(GEOIP_FILENAME));
QString error;
m_geoIPDatabase = GeoIPDatabase::load(filepath, error);
if (m_geoIPDatabase)
Logger::instance()->addMessage(tr("GeoIP database loaded. Type: %1. Build time: %2.")
.arg(m_geoIPDatabase->type()).arg(m_geoIPDatabase->buildEpoch().toString()),
Log::INFO);
else
Logger::instance()->addMessage(tr("Couldn't load GeoIP database. Reason: %1").arg(error), Log::WARNING);
manageDatabaseUpdate();
}
void GeoIPManager::manageDatabaseUpdate()
{
if (!m_geoIPDatabase || (m_geoIPDatabase->buildEpoch().daysTo(QDateTime::currentDateTimeUtc()) >= UPDATE_INTERVAL))
downloadDatabaseFile();
}
void GeoIPManager::downloadDatabaseFile()
{
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(DATABASE_URL);
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(downloadFinished(QString, QByteArray)));
connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(downloadFailed(QString, QString)));
}
QString GeoIPManager::lookup(const QHostAddress &hostAddr) const
{
if (m_enabled && m_geoIPDatabase) {
QString *country = m_cache.object(hostAddr);
if (country)
return *country;
QString code = m_geoIPDatabase->lookup(hostAddr);
m_cache.insert(hostAddr, new QString(code));
return code;
}
return QString();
}
// http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm
QString GeoIPManager::CountryName(const QString &countryISOCode)
{
static QHash<QString, QString> countries;
static bool initialized = false;
if (!initialized) {
countries[QString()] = "N/A";
countries["AP"] = "Asia/Pacific Region";
countries["EU"] = "Europe";
countries["AD"] = "Andorra";
countries["AE"] = "United Arab Emirates";
countries["AF"] = "Afghanistan";
countries["AG"] = "Antigua and Barbuda";
countries["AI"] = "Anguilla";
countries["AL"] = "Albania";
countries["AM"] = "Armenia";
countries["AN"] = "Netherlands Antilles";
countries["AO"] = "Angola";
countries["AQ"] = "Antarctica";
countries["AR"] = "Argentina";
countries["AS"] = "American Samoa";
countries["AT"] = "Austria";
countries["AU"] = "Australia";
countries["AW"] = "Aruba";
countries["AZ"] = "Azerbaijan";
countries["BA"] = "Bosnia and Herzegovina";
countries["BB"] = "Barbados";
countries["BD"] = "Bangladesh";
countries["BE"] = "Belgium";
countries["BF"] = "Burkina Faso";
countries["BG"] = "Bulgaria";
countries["BH"] = "Bahrain";
countries["BI"] = "Burundi";
countries["BJ"] = "Benin";
countries["BM"] = "Bermuda";
countries["BN"] = "Brunei Darussalam";
countries["BO"] = "Bolivia";
countries["BR"] = "Brazil";
countries["BS"] = "Bahamas";
countries["BT"] = "Bhutan";
countries["BV"] = "Bouvet Island";
countries["BW"] = "Botswana";
countries["BY"] = "Belarus";
countries["BZ"] = "Belize";
countries["CA"] = "Canada";
countries["CC"] = "Cocos (Keeling) Islands";
countries["CD"] = "Congo, The Democratic Republic of the";
countries["CF"] = "Central African Republic";
countries["CG"] = "Congo";
countries["CH"] = "Switzerland";
countries["CI"] = "Cote D'Ivoire";
countries["CK"] = "Cook Islands";
countries["CL"] = "Chile";
countries["CM"] = "Cameroon";
countries["CN"] = "China";
countries["CO"] = "Colombia";
countries["CR"] = "Costa Rica";
countries["CU"] = "Cuba";
countries["CV"] = "Cape Verde";
countries["CX"] = "Christmas Island";
countries["CY"] = "Cyprus";
countries["CZ"] = "Czech Republic";
countries["DE"] = "Germany";
countries["DJ"] = "Djibouti";
countries["DK"] = "Denmark";
countries["DM"] = "Dominica";
countries["DO"] = "Dominican Republic";
countries["DZ"] = "Algeria";
countries["EC"] = "Ecuador";
countries["EE"] = "Estonia";
countries["EG"] = "Egypt";
countries["EH"] = "Western Sahara";
countries["ER"] = "Eritrea";
countries["ES"] = "Spain";
countries["ET"] = "Ethiopia";
countries["FI"] = "Finland";
countries["FJ"] = "Fiji";
countries["FK"] = "Falkland Islands (Malvinas)";
countries["FM"] = "Micronesia, Federated States of";
countries["FO"] = "Faroe Islands";
countries["FR"] = "France";
countries["FX"] = "France, Metropolitan";
countries["GA"] = "Gabon";
countries["GB"] = "United Kingdom";
countries["GD"] = "Grenada";
countries["GE"] = "Georgia";
countries["GF"] = "French Guiana";
countries["GH"] = "Ghana";
countries["GI"] = "Gibraltar";
countries["GL"] = "Greenland";
countries["GM"] = "Gambia";
countries["GN"] = "Guinea";
countries["GP"] = "Guadeloupe";
countries["GQ"] = "Equatorial Guinea";
countries["GR"] = "Greece";
countries["GS"] = "South Georgia and the South Sandwich Islands";
countries["GT"] = "Guatemala";
countries["GU"] = "Guam";
countries["GW"] = "Guinea-Bissau";
countries["GY"] = "Guyana";
countries["HK"] = "Hong Kong";
countries["HM"] = "Heard Island and McDonald Islands";
countries["HN"] = "Honduras";
countries["HR"] = "Croatia";
countries["HT"] = "Haiti";
countries["HU"] = "Hungary";
countries["ID"] = "Indonesia";
countries["IE"] = "Ireland";
countries["IL"] = "Israel";
countries["IN"] = "India";
countries["IO"] = "British Indian Ocean Territory";
countries["IQ"] = "Iraq";
countries["IR"] = "Iran, Islamic Republic of";
countries["IS"] = "Iceland";
countries["IT"] = "Italy";
countries["JM"] = "Jamaica";
countries["JO"] = "Jordan";
countries["JP"] = "Japan";
countries["KE"] = "Kenya";
countries["KG"] = "Kyrgyzstan";
countries["KH"] = "Cambodia";
countries["KI"] = "Kiribati";
countries["KM"] = "Comoros";
countries["KN"] = "Saint Kitts and Nevis";
countries["KP"] = "Korea, Democratic People's Republic of";
countries["KR"] = "Korea, Republic of";
countries["KW"] = "Kuwait";
countries["KY"] = "Cayman Islands";
countries["KZ"] = "Kazakhstan";
countries["LA"] = "Lao People's Democratic Republic";
countries["LB"] = "Lebanon";
countries["LC"] = "Saint Lucia";
countries["LI"] = "Liechtenstein";
countries["LK"] = "Sri Lanka";
countries["LR"] = "Liberia";
countries["LS"] = "Lesotho";
countries["LT"] = "Lithuania";
countries["LU"] = "Luxembourg";
countries["LV"] = "Latvia";
countries["LY"] = "Libyan Arab Jamahiriya";
countries["MA"] = "Morocco";
countries["MC"] = "Monaco";
countries["MD"] = "Moldova, Republic of";
countries["MG"] = "Madagascar";
countries["MH"] = "Marshall Islands";
countries["MK"] = "Macedonia";
countries["ML"] = "Mali";
countries["MM"] = "Myanmar";
countries["MN"] = "Mongolia";
countries["MO"] = "Macau";
countries["MP"] = "Northern Mariana Islands";
countries["MQ"] = "Martinique";
countries["MR"] = "Mauritania";
countries["MS"] = "Montserrat";
countries["MT"] = "Malta";
countries["MU"] = "Mauritius";
countries["MV"] = "Maldives";
countries["MW"] = "Malawi";
countries["MX"] = "Mexico";
countries["MY"] = "Malaysia";
countries["MZ"] = "Mozambique";
countries["NA"] = "Namibia";
countries["NC"] = "New Caledonia";
countries["NE"] = "Niger";
countries["NF"] = "Norfolk Island";
countries["NG"] = "Nigeria";
countries["NI"] = "Nicaragua";
countries["NL"] = "Netherlands";
countries["NO"] = "Norway";
countries["NP"] = "Nepal";
countries["NR"] = "Nauru";
countries["NU"] = "Niue";
countries["NZ"] = "New Zealand";
countries["OM"] = "Oman";
countries["PA"] = "Panama";
countries["PE"] = "Peru";
countries["PF"] = "French Polynesia";
countries["PG"] = "Papua New Guinea";
countries["PH"] = "Philippines";
countries["PK"] = "Pakistan";
countries["PL"] = "Poland";
countries["PM"] = "Saint Pierre and Miquelon";
countries["PN"] = "Pitcairn Islands";
countries["PR"] = "Puerto Rico";
countries["PS"] = "Palestinian Territory";
countries["PT"] = "Portugal";
countries["PW"] = "Palau";
countries["PY"] = "Paraguay";
countries["QA"] = "Qatar";
countries["RE"] = "Reunion";
countries["RO"] = "Romania";
countries["RU"] = "Russian Federation";
countries["RW"] = "Rwanda";
countries["SA"] = "Saudi Arabia";
countries["SB"] = "Solomon Islands";
countries["SC"] = "Seychelles";
countries["SD"] = "Sudan";
countries["SE"] = "Sweden";
countries["SG"] = "Singapore";
countries["SH"] = "Saint Helena";
countries["SI"] = "Slovenia";
countries["SJ"] = "Svalbard and Jan Mayen";
countries["SK"] = "Slovakia";
countries["SL"] = "Sierra Leone";
countries["SM"] = "San Marino";
countries["SN"] = "Senegal";
countries["SO"] = "Somalia";
countries["SR"] = "Suriname";
countries["ST"] = "Sao Tome and Principe";
countries["SV"] = "El Salvador";
countries["SY"] = "Syrian Arab Republic";
countries["SZ"] = "Swaziland";
countries["TC"] = "Turks and Caicos Islands";
countries["TD"] = "Chad";
countries["TF"] = "French Southern Territories";
countries["TG"] = "Togo";
countries["TH"] = "Thailand";
countries["TJ"] = "Tajikistan";
countries["TK"] = "Tokelau";
countries["TM"] = "Turkmenistan";
countries["TN"] = "Tunisia";
countries["TO"] = "Tonga";
countries["TL"] = "Timor-Leste";
countries["TR"] = "Turkey";
countries["TT"] = "Trinidad and Tobago";
countries["TV"] = "Tuvalu";
countries["TW"] = "Taiwan";
countries["TZ"] = "Tanzania, United Republic of";
countries["UA"] = "Ukraine";
countries["UG"] = "Uganda";
countries["UM"] = "United States Minor Outlying Islands";
countries["US"] = "United States";
countries["UY"] = "Uruguay";
countries["UZ"] = "Uzbekistan";
countries["VA"] = "Holy See (Vatican City State)";
countries["VC"] = "Saint Vincent and the Grenadines";
countries["VE"] = "Venezuela";
countries["VG"] = "Virgin Islands, British";
countries["VI"] = "Virgin Islands, U.S.";
countries["VN"] = "Vietnam";
countries["VU"] = "Vanuatu";
countries["WF"] = "Wallis and Futuna";
countries["WS"] = "Samoa";
countries["YE"] = "Yemen";
countries["YT"] = "Mayotte";
countries["RS"] = "Serbia";
countries["ZA"] = "South Africa";
countries["ZM"] = "Zambia";
countries["ME"] = "Montenegro";
countries["ZW"] = "Zimbabwe";
countries["A1"] = "Anonymous Proxy";
countries["A2"] = "Satellite Provider";
countries["O1"] = "Other";
countries["AX"] = "Aland Islands";
countries["GG"] = "Guernsey";
countries["IM"] = "Isle of Man";
countries["JE"] = "Jersey";
countries["BL"] = "Saint Barthelemy";
countries["MF"] = "Saint Martin";
initialized = true;
}
return countries.value(countryISOCode, "N/A");
}
void GeoIPManager::configure()
{
const bool enabled = Preferences::instance()->resolvePeerCountries();
if (m_enabled != enabled) {
m_enabled = enabled;
if (m_enabled && !m_geoIPDatabase)
loadDatabase();
}
}
void GeoIPManager::downloadFinished(const QString &url, QByteArray data)
{
Q_UNUSED(url);
if (!Utils::Gzip::uncompress(data, data)) {
Logger::instance()->addMessage(tr("Could not uncompress GeoIP database file."), Log::WARNING);
return;
}
QString error;
GeoIPDatabase *geoIPDatabase = GeoIPDatabase::load(data, error);
if (geoIPDatabase) {
if (!m_geoIPDatabase || (geoIPDatabase->buildEpoch() > m_geoIPDatabase->buildEpoch())) {
if (m_geoIPDatabase)
delete m_geoIPDatabase;
m_geoIPDatabase = geoIPDatabase;
Logger::instance()->addMessage(tr("GeoIP database loaded. Type: %1. Build time: %2.")
.arg(m_geoIPDatabase->type()).arg(m_geoIPDatabase->buildEpoch().toString()),
Log::INFO);
QString targetPath = Utils::Fs::expandPathAbs(
Utils::Fs::QDesktopServicesDataLocation() + GEOIP_FOLDER);
if (!QDir(targetPath).exists())
QDir().mkpath(targetPath);
QFile targetFile(QString("%1/%2").arg(targetPath).arg(GEOIP_FILENAME));
if (!targetFile.open(QFile::WriteOnly) || (targetFile.write(data) == -1)) {
Logger::instance()->addMessage(
tr("Couldn't save downloaded GeoIP database file."), Log::WARNING);
}
else {
Logger::instance()->addMessage(tr("Successfully updated GeoIP database."), Log::INFO);
}
}
else {
delete geoIPDatabase;
}
}
else {
Logger::instance()->addMessage(tr("Couldn't load GeoIP database. Reason: %1").arg(error), Log::WARNING);
}
}
void GeoIPManager::downloadFailed(const QString &url, const QString &reason)
{
Q_UNUSED(url);
Logger::instance()->addMessage(tr("Couldn't download GeoIP database file. Reason: %1").arg(reason), Log::WARNING);
}

77
src/core/net/geoipmanager.h

@ -0,0 +1,77 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#ifndef NET_GEOIPMANAGER_H
#define NET_GEOIPMANAGER_H
#include <QObject>
#include <QCache>
class QHostAddress;
class QString;
class GeoIPDatabase;
namespace Net
{
class GeoIPManager : public QObject
{
Q_OBJECT
public:
static void initInstance();
static void freeInstance();
static GeoIPManager *instance();
QString lookup(const QHostAddress &hostAddr) const;
static QString CountryName(const QString &countryISOCode);
private slots:
void configure();
void downloadFinished(const QString &url, QByteArray data);
void downloadFailed(const QString &url, const QString &reason);
private:
GeoIPManager();
~GeoIPManager();
void loadDatabase();
void manageDatabaseUpdate();
void downloadDatabaseFile();
bool m_enabled;
GeoIPDatabase *m_geoIPDatabase;
mutable QCache<QHostAddress, QString> m_cache;
static GeoIPManager *m_instance;
};
}
#endif // NET_GEOIPMANAGER_H

631
src/core/net/private/geoipdatabase.cpp

@ -0,0 +1,631 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#include <QDebug>
#include <QCoreApplication>
#include <QVariant>
#include <QHash>
#include <QList>
#include <QScopedArrayPointer>
#include <QScopedPointer>
#include <QHostAddress>
#include <QDateTime>
#include <QFile>
#include "core/types.h"
#include "geoipdatabase.h"
struct Node
{
quint32 left;
quint32 right;
};
struct GeoIPData
{
// Metadata
quint16 ipVersion;
quint16 recordSize;
quint32 nodeCount;
QDateTime buildEpoch;
// Search data
QList<Node> index;
QHash<quint32, QString> countries;
};
namespace
{
const quint32 __ENDIAN_TEST__ = 0x00000001;
const bool __IS_LITTLE_ENDIAN__ = (reinterpret_cast<const uchar *>(&__ENDIAN_TEST__)[0] == 0x01);
BEGIN_SCOPED_ENUM(DataType)
{
Unknown = 0,
Pointer = 1,
String = 2,
Double = 3,
Bytes = 4,
Integer16 = 5,
Integer32 = 6,
Map = 7,
SignedInteger32 = 8,
Integer64 = 9,
Integer128 = 10,
Array = 11,
DataCacheContainer = 12,
EndMarker = 13,
Boolean = 14,
Float = 15
}
END_SCOPED_ENUM
struct DataFieldDescriptor
{
DataType fieldType;
union
{
quint32 fieldSize;
quint32 offset; // Pointer
};
};
const int MAX_FILE_SIZE = 10485760; // 10MB
const char DB_TYPE[] = "GeoLite2-Country";
const quint32 MAX_METADATA_SIZE = 131072; // 128KB
const char METADATA_BEGIN_MARK[] = "\xab\xcd\xefMaxMind.com";
const char DATA_SECTION_SEPARATOR[16] = { 0 };
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
Q_IPV6ADDR createMappedAddress(quint32 ip4);
#endif
class Loader
{
Q_DECLARE_TR_FUNCTIONS(GeoIPDatabase)
public:
GeoIPData *load(const QString &filename);
GeoIPData *load(const QByteArray &data);
QString error() const;
private:
bool parseMetadata(const QVariantHash &metadata);
bool loadDB();
QVariantHash readMetadata();
QVariant readDataField(quint32 &offset);
bool readDataFieldDescriptor(quint32 &offset, DataFieldDescriptor &out);
void fromBigEndian(uchar *buf, quint32 len);
QVariant readMapValue(quint32 &offset, quint32 count);
QVariant readArrayValue(quint32 &offset, quint32 count);
template<typename T>
QVariant readPlainValue(quint32 &offset, quint8 len)
{
T value = 0;
const uchar *const data = m_data + offset;
const quint32 availSize = m_size - offset;
if ((len > 0) && (len <= sizeof(T) && (availSize >= len))) {
// copy input data to last 'len' bytes of 'value'
uchar *dst = reinterpret_cast<uchar *>(&value) + (sizeof(T) - len);
memcpy(dst, data, len);
fromBigEndian(reinterpret_cast<uchar *>(&value), sizeof(T));
offset += len;
}
return QVariant::fromValue(value);
}
private:
const uchar *m_data;
quint32 m_size;
QString m_error;
GeoIPData *m_geoIPData;
};
}
// GeoIPDatabase
GeoIPDatabase::GeoIPDatabase(GeoIPData *geoIPData)
: m_geoIPData(geoIPData)
{
}
GeoIPDatabase *GeoIPDatabase::load(const QString &filename, QString &error)
{
GeoIPDatabase *db = 0;
Loader loader;
GeoIPData *geoIPData = loader.load(filename);
if (!geoIPData)
error = loader.error();
else
db = new GeoIPDatabase(geoIPData);
return db;
}
GeoIPDatabase *GeoIPDatabase::load(const QByteArray &data, QString &error)
{
GeoIPDatabase *db = 0;
Loader loader;
GeoIPData *geoIPData = loader.load(data);
if (!geoIPData)
error = loader.error();
else
db = new GeoIPDatabase(geoIPData);
return db;
}
GeoIPDatabase::~GeoIPDatabase()
{
delete m_geoIPData;
}
QString GeoIPDatabase::type() const
{
return DB_TYPE;
}
quint16 GeoIPDatabase::ipVersion() const
{
return m_geoIPData->ipVersion;
}
QDateTime GeoIPDatabase::buildEpoch() const
{
return m_geoIPData->buildEpoch;
}
QString GeoIPDatabase::lookup(const QHostAddress &hostAddr) const
{
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
Q_IPV6ADDR addr = hostAddr.protocol() == QAbstractSocket::IPv4Protocol
? createMappedAddress(hostAddr.toIPv4Address())
: hostAddr.toIPv6Address();
#else
Q_IPV6ADDR addr = hostAddr.toIPv6Address();
#endif
const quint32 nodeCount = static_cast<quint32>(m_geoIPData->index.size());
Node node = m_geoIPData->index[0];
for (int i = 0; i < 16; ++i) {
for (int j = 0; j < 8; ++j) {
bool right = static_cast<bool>((addr[i] >> (7 - j)) & 1);
quint32 id = (right ? node.right : node.left);
if (id == nodeCount)
return QString();
else if (id > nodeCount)
return m_geoIPData->countries[id];
else
node = m_geoIPData->index[id];
}
}
return QString();
}
namespace
{
// Loader
GeoIPData *Loader::load(const QString &filename)
{
QFile file(filename);
if (file.size() > MAX_FILE_SIZE) {
m_error = tr("Unsupported database file size.");
return 0;
}
if (!file.open(QFile::ReadOnly)) {
m_error = file.errorString();
return 0;
}
m_size = file.size();
QScopedArrayPointer<uchar> data(new uchar[m_size]);
m_data = data.data();
if (file.read((char *)m_data, m_size) != m_size) {
m_error = file.errorString();
return 0;
}
QScopedPointer<GeoIPData> geoIPData(new GeoIPData);
m_geoIPData = geoIPData.data();
if (!parseMetadata(readMetadata()) || !loadDB())
return 0;
return geoIPData.take();
}
GeoIPData *Loader::load(const QByteArray &data)
{
if (data.size() > MAX_FILE_SIZE) {
m_error = tr("Unsupported database file size.");
return 0;
}
m_size = data.size();
m_data = reinterpret_cast<const uchar *>(data.constData());
QScopedPointer<GeoIPData> geoIPData(new GeoIPData);
m_geoIPData = geoIPData.data();
if (!parseMetadata(readMetadata()) || !loadDB())
return 0;
return geoIPData.take();
}
QString Loader::error() const
{
return m_error;
}
#define CHECK_METADATA_REQ(key, type) \
if (!metadata.contains(#key)) { \
m_error = errMsgNotFound.arg(#key); \
return false; \
} \
else if (metadata.value(#key).userType() != QMetaType::type) { \
m_error = errMsgInvalid.arg(#key); \
return false; \
}
#define CHECK_METADATA_OPT(key, type) \
if (metadata.contains(#key)) { \
if (metadata.value(#key).userType() != QMetaType::type) { \
m_error = errMsgInvalid.arg(#key); \
return false; \
} \
}
bool Loader::parseMetadata(const QVariantHash &metadata)
{
const QString errMsgNotFound = tr("Metadata error: '%1' entry not found.");
const QString errMsgInvalid = tr("Metadata error: '%1' entry has invalid type.");
qDebug() << "Parsing MaxMindDB metadata...";
CHECK_METADATA_REQ(binary_format_major_version, UShort);
CHECK_METADATA_REQ(binary_format_minor_version, UShort);
uint versionMajor = metadata.value("binary_format_major_version").toUInt();
uint versionMinor = metadata.value("binary_format_minor_version").toUInt();
if (versionMajor != 2) {
m_error = tr("Unsupported database version: %1.%2").arg(versionMajor).arg(versionMinor);
return false;
}
CHECK_METADATA_REQ(ip_version, UShort);
m_geoIPData->ipVersion = metadata.value("ip_version").value<quint16>();
if (m_geoIPData->ipVersion != 6) {
m_error = tr("Unsupported IP version: %1").arg(m_geoIPData->ipVersion);
return false;
}
CHECK_METADATA_REQ(record_size, UShort);
m_geoIPData->recordSize = metadata.value("record_size").value<quint16>();
if (m_geoIPData->recordSize != 24) {
m_error = tr("Unsupported record size: %1").arg(m_geoIPData->recordSize);
return false;
}
CHECK_METADATA_REQ(node_count, UInt);
m_geoIPData->nodeCount = metadata.value("node_count").value<quint32>();
CHECK_METADATA_REQ(database_type, QString);
QString dbType = metadata.value("database_type").toString();
if (dbType != DB_TYPE) {
m_error = tr("Invalid database type: %1").arg(dbType);
return false;
}
CHECK_METADATA_REQ(build_epoch, ULongLong);
m_geoIPData->buildEpoch = QDateTime::fromTime_t(metadata.value("build_epoch").toULongLong());
CHECK_METADATA_OPT(languages, QVariantList);
CHECK_METADATA_OPT(description, QVariantHash);
return true;
}
bool Loader::loadDB()
{
qDebug() << "Parsing MaxMindDB index tree...";
const int nodeSize = m_geoIPData->recordSize / 4; // in bytes
const int indexSize = m_geoIPData->nodeCount * nodeSize;
if ((m_size < (indexSize + sizeof(DATA_SECTION_SEPARATOR)))
|| (memcmp(m_data + indexSize, DATA_SECTION_SEPARATOR, sizeof(DATA_SECTION_SEPARATOR)) != 0)) {
m_error = tr("Database corrupted: no data section found.");
return false;
}
m_geoIPData->index.reserve(m_geoIPData->nodeCount);
const int recordBytes = nodeSize / 2;
const uchar *ptr = m_data;
bool left = true;
Node node;
for (quint32 i = 0; i < (2 * m_geoIPData->nodeCount); ++i) {
uchar buf[4] = { 0 };
memcpy(&buf[4 - recordBytes], ptr, recordBytes);
fromBigEndian(buf, 4);
quint32 id = *(reinterpret_cast<quint32 *>(buf));
if ((id > m_geoIPData->nodeCount) && !m_geoIPData->countries.contains(id)) {
const quint32 offset = id - m_geoIPData->nodeCount - sizeof(DATA_SECTION_SEPARATOR);
quint32 tmp = offset + indexSize + sizeof(DATA_SECTION_SEPARATOR);
QVariant val = readDataField(tmp);
if (val.userType() == QMetaType::QVariantHash) {
m_geoIPData->countries[id] = val.toHash()["country"].toHash()["iso_code"].toString();
}
else if (val.userType() == QVariant::Invalid) {
m_error = tr("Database corrupted: invalid data type at DATA@%1").arg(offset, 8, 16, QLatin1Char('0'));
return false;
}
else {
m_error = tr("Invalid database: unsupported data type at DATA@%1").arg(offset, 8, 16, QLatin1Char('0'));
return false;
}
}
if (left) {
node.left = id;
}
else {
node.right = id;
m_geoIPData->index << node;
}
left = !left;
ptr += recordBytes;
}
return true;
}
QVariantHash Loader::readMetadata()
{
const char *ptr = reinterpret_cast<const char *>(m_data);
quint32 size = m_size;
if (m_size > MAX_METADATA_SIZE) {
ptr += m_size - MAX_METADATA_SIZE;
size = MAX_METADATA_SIZE;
}
const QByteArray data = QByteArray::fromRawData(ptr, size);
int index = data.lastIndexOf(METADATA_BEGIN_MARK);
if (index >= 0) {
if (m_size > MAX_METADATA_SIZE)
index += (m_size - MAX_METADATA_SIZE); // from begin of all data
quint32 offset = static_cast<quint32>(index + strlen(METADATA_BEGIN_MARK));
QVariant metadata = readDataField(offset);
m_size = index; // truncate m_size to not contain metadata section
if (metadata.userType() == QMetaType::QVariantHash)
return metadata.toHash();
}
return QVariantHash();
}
QVariant Loader::readDataField(quint32 &offset)
{
DataFieldDescriptor descr;
if (!readDataFieldDescriptor(offset, descr))
return QVariant();
quint32 locOffset = offset;
bool usePointer = false;
if (descr.fieldType == DataType::Pointer) {
usePointer = true;
// convert offset from data section to global
locOffset = descr.offset + (m_geoIPData->nodeCount * m_geoIPData->recordSize / 4) + sizeof(DATA_SECTION_SEPARATOR);
if (!readDataFieldDescriptor(locOffset, descr))
return QVariant();
}
QVariant fieldValue;
switch (descr.fieldType) {
case DataType::Pointer:
qDebug() << "* Illegal Pointer using";
break;
case DataType::String:
fieldValue = QString::fromUtf8(reinterpret_cast<const char *>(m_data + locOffset), descr.fieldSize);
locOffset += descr.fieldSize;
break;
case DataType::Double:
if (descr.fieldSize == 8)
fieldValue = readPlainValue<double>(locOffset, descr.fieldSize);
else
qDebug() << "* Invalid field size for type: Double";
break;
case DataType::Bytes:
fieldValue = QByteArray(reinterpret_cast<const char *>(m_data + locOffset), descr.fieldSize);
locOffset += descr.fieldSize;
break;
case DataType::Integer16:
fieldValue = readPlainValue<quint16>(locOffset, descr.fieldSize);
break;
case DataType::Integer32:
fieldValue = readPlainValue<quint32>(locOffset, descr.fieldSize);
break;
case DataType::Map:
fieldValue = readMapValue(locOffset, descr.fieldSize);
break;
case DataType::SignedInteger32:
fieldValue = readPlainValue<qint32>(locOffset, descr.fieldSize);
break;
case DataType::Integer64:
fieldValue = readPlainValue<quint64>(locOffset, descr.fieldSize);
break;
case DataType::Integer128:
qDebug() << "* Unsupported data type: Integer128";
break;
case DataType::Array:
fieldValue = readArrayValue(locOffset, descr.fieldSize);
break;
case DataType::DataCacheContainer:
qDebug() << "* Unsupported data type: DataCacheContainer";
break;
case DataType::EndMarker:
qDebug() << "* Unsupported data type: EndMarker";
break;
case DataType::Boolean:
fieldValue = QVariant::fromValue(static_cast<bool>(descr.fieldSize));
break;
case DataType::Float:
if (descr.fieldSize == 4)
fieldValue = readPlainValue<float>(locOffset, descr.fieldSize);
else
qDebug() << "* Invalid field size for type: Float";
break;
}
if (!usePointer)
offset = locOffset;
return fieldValue;
}
bool Loader::readDataFieldDescriptor(quint32 &offset, DataFieldDescriptor &out)
{
const uchar *dataPtr = m_data + offset;
int availSize = m_size - offset;
if (availSize < 1) return false;
out.fieldType = static_cast<DataType>((dataPtr[0] & 0xE0) >> 5);
if (out.fieldType == DataType::Pointer) {
int size = ((dataPtr[0] & 0x18) >> 3);
if (availSize < (size + 2)) return false;
if (size == 0)
out.offset = ((dataPtr[0] & 0x07) << 8) + dataPtr[1];
else if (size == 1)
out.offset = ((dataPtr[0] & 0x07) << 16) + (dataPtr[1] << 8) + dataPtr[2] + 2048;
else if (size == 2)
out.offset = ((dataPtr[0] & 0x07) << 24) + (dataPtr[1] << 16) + (dataPtr[2] << 8) + dataPtr[3] + 526336;
else if (size == 3)
out.offset = (dataPtr[1] << 24) + (dataPtr[2] << 16) + (dataPtr[3] << 8) + dataPtr[4];
offset += size + 2;
return true;
}
out.fieldSize = dataPtr[0] & 0x1F;
if (out.fieldSize <= 28) {
if (out.fieldType == DataType::Unknown) {
out.fieldType = static_cast<DataType>(dataPtr[1] + 7);
if ((out.fieldType <= DataType::Map) || (out.fieldType > DataType::Float) || (availSize < 3))
return false;
offset += 2;
}
else {
offset += 1;
}
}
else if (out.fieldSize == 29) {
if (availSize < 2) return false;
out.fieldSize = dataPtr[1] + 29;
offset += 2;
}
else if (out.fieldSize == 30) {
if (availSize < 3) return false;
out.fieldSize = (dataPtr[1] << 8) + dataPtr[2] + 285;
offset += 3;
}
else if (out.fieldSize == 31) {
if (availSize < 4) return false;
out.fieldSize = (dataPtr[1] << 16) + (dataPtr[2] << 8) + dataPtr[3] + 65821;
offset += 4;
}
return true;
}
void Loader::fromBigEndian(uchar *buf, quint32 len)
{
if (__IS_LITTLE_ENDIAN__)
std::reverse(buf, buf + len);
}
QVariant Loader::readMapValue(quint32 &offset, quint32 count)
{
QVariantHash map;
for (quint32 i = 0; i < count; ++i) {
QVariant field = readDataField(offset);
if (field.userType() != QMetaType::QString)
return QVariant();
QString key = field.toString();
field = readDataField(offset);
if (field.userType() == QVariant::Invalid)
return QVariant();
map[key] = field;
}
return map;
}
QVariant Loader::readArrayValue(quint32 &offset, quint32 count)
{
QVariantList array;
for (quint32 i = 0; i < count; ++i) {
QVariant field = readDataField(offset);
if (field.userType() == QVariant::Invalid)
return QVariant();
array.append(field);
}
return array;
}
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
Q_IPV6ADDR createMappedAddress(quint32 ip4)
{
Q_IPV6ADDR ip6;
memset(&ip6, 0, sizeof(ip6));
int i;
for (i = 15; ip4 != 0; i--) {
ip6[i] = ip4 & 0xFF;
ip4 >>= 8;
}
ip6[11] = 0xFF;
ip6[10] = 0xFF;
return ip6;
}
#endif
}

48
src/gui/geoip/geoipmanager.h → src/core/net/private/geoipdatabase.h

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt4 and libtorrent. * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2010 Christophe Dumez * Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -24,35 +24,37 @@
* modify file(s), you may extend this exception to your version of the file(s), * modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this * but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version. * exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/ */
#ifndef GEOIPMANAGER_H #ifndef GEOIPDATABASE_H
#define GEOIPMANAGER_H #define GEOIPDATABASE_H
#include <QString> #include <QtGlobal>
#include <QIcon>
namespace libtorrent { class QHostAddress;
class session; class QString;
} class QByteArray;
class QDateTime;
class GeoIPManager : public QObject { struct GeoIPData;
Q_OBJECT
class GeoIPDatabase
{
public: public:
static void loadDatabase(libtorrent::session *s); static GeoIPDatabase *load(const QString &filename, QString &error);
static QIcon CountryISOCodeToIcon(const QString &iso); static GeoIPDatabase *load(const QByteArray &data, QString &error);
static QString CountryISOCodeToName(const QString &iso);
~GeoIPDatabase();
QString type() const;
quint16 ipVersion() const;
QDateTime buildEpoch() const;
QString lookup(const QHostAddress &hostAddr) const;
private: private:
static QString geoipFolder(bool embedded=false); GeoIPDatabase(GeoIPData *geoIPData);
static QString geoipDBpath(bool embedded=false);
#ifdef WITH_GEOIP_EMBEDDED
static void exportEmbeddedDb();
#endif
};
GeoIPData *m_geoIPData;
};
#endif // GEOIP_H #endif // GEOIPDATABASE_H

12
src/gui/geoip/README

@ -1,12 +0,0 @@
If you wish to embed GeoIP database into qBittorrent executable, please download put GeoIP.dat in this folder.
GeoIP Database can be downloaded from here:
* http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
Note that the database should be uncompressed.
Embedding GeoIP database into qBittorrent executable is advised for:
* Windows
* Mac OS X
* Linux distributions that don't provide GeoIP database in a separate package
On Linux operating system, since this is not the default behavior, you also need to pass --with-geoip-database-embedded parameter to the configure file.

19
src/gui/geoip/geoip.pri

@ -1,19 +0,0 @@
INCLUDEPATH += $$PWD
HEADERS += $$PWD/geoipmanager.h
SOURCES += $$PWD/geoipmanager.cpp
# Add GeoIP resource file if the GeoIP database
# should be embedded in qBittorrent executable
contains(DEFINES, WITH_GEOIP_EMBEDDED) {
exists("GeoIP.dat") {
message("GeoIP.dat was found in src/gui/geoip/.")
RESOURCES += $$PWD/geoip.qrc
} else {
DEFINES -= WITH_GEOIP_EMBEDDED
error("GeoIP.dat was not found in src/gui/geoip/ folder, please follow instructions in src/gui/geoip/README.")
}
} else {
message("GeoIP database will not be embedded in qBittorrent executable.")
}

5
src/gui/geoip/geoip.qrc

@ -1,5 +0,0 @@
<RCC>
<qresource prefix="/geoip">
<file>GeoIP.dat</file>
</qresource>
</RCC>

203
src/gui/geoip/geoipmanager.cpp

@ -1,203 +0,0 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2010 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#include "geoipmanager.h"
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2010 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#include <QDir>
#include <QFile>
#include <QChar>
#include "core/utils/fs.h"
#include <libtorrent/session.hpp>
using namespace libtorrent;
QString GeoIPManager::geoipFolder(bool embedded) {
#ifdef WITH_GEOIP_EMBEDDED
if (embedded)
return ":/geoip/";
return Utils::Fs::QDesktopServicesDataLocation()+"geoip"+"/";
#else
Q_UNUSED(embedded);
if (QFile::exists("/usr/local/share/GeoIP/GeoIP.dat"))
return "/usr/local/share/GeoIP/";
if (QFile::exists("/var/lib/GeoIP/GeoIP.dat"))
return "/var/lib/GeoIP/";
return "/usr/share/GeoIP/";
#endif
}
QString GeoIPManager::geoipDBpath(bool embedded) {
return geoipFolder(embedded)+"GeoIP.dat";
}
#ifdef WITH_GEOIP_EMBEDDED
void GeoIPManager::exportEmbeddedDb() {
if (!QFile::exists(geoipDBpath(false)) || QFile(geoipDBpath(false)).size() != QFile(geoipDBpath(true)).size()) { // Export is required
qDebug("A local Geoip database update is required, proceeding...");
// Create geoip folder is necessary
QDir gfolder(geoipFolder(false));
if (!gfolder.exists()) {
if (!gfolder.mkpath(geoipFolder(false))) {
std::cerr << "Failed to create geoip folder at " << qPrintable(geoipFolder(false)) << std::endl;
return;
}
}
// Remove destination files
if (QFile::exists(geoipDBpath(false)))
Utils::Fs::forceRemove(geoipDBpath(false));
// Copy from executable to hard disk
qDebug("%s -> %s", qPrintable(geoipDBpath(true)), qPrintable(geoipDBpath(false)));
if (!QFile::copy(geoipDBpath(true), geoipDBpath(false))) {
std::cerr << "ERROR: Failed to copy geoip.dat from executable to hard disk" << std::endl;
}
qDebug("Local Geoip database was updated");
}
}
#endif
void GeoIPManager::loadDatabase(session *s) {
#ifdef WITH_GEOIP_EMBEDDED
exportEmbeddedDb();
#endif
if (QFile::exists(geoipDBpath(false))) {
qDebug("Loading GeoIP database from %s...", qPrintable(geoipDBpath(false)));
s->load_country_db(geoipDBpath(false).toLocal8Bit().constData());
} else {
qDebug("ERROR: Impossible to find local Geoip Database");
}
}
const char country_code[253][3] =
{ "--","AP","EU","AD","AE","AF","AG","AI","AL","AM","AN",
"AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB",
"BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO",
"BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD",
"CF","CG","CH","CI","CK","CL","CM","CN","CO","CR",
"CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO",
"DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ",
"FK","FM","FO","FR","FX","GA","GB","GD","GE","GF",
"GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT",
"GU","GW","GY","HK","HM","HN","HR","HT","HU","ID",
"IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO",
"JP","KE","KG","KH","KI","KM","KN","KP","KR","KW",
"KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT",
"LU","LV","LY","MA","MC","MD","MG","MH","MK","ML",
"MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV",
"MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI",
"NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF",
"PG","PH","PK","PL","PM","PN","PR","PS","PT","PW",
"PY","QA","RE","RO","RU","RW","SA","SB","SC","SD",
"SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO",
"SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH",
"TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW",
"TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE",
"VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA",
"ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE",
"BL","MF"};
static const uint num_countries = (unsigned)(sizeof(country_code)/sizeof(country_code[0]));
const char * country_name[253] =
{"N/A","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles",
"Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados",
"Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia",
"Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the",
"Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica",
"Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic",
"Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji",
"Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana",
"Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala",
"Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia",
"Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan",
"Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait",
"Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania",
"Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali",
"Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives",
"Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua",
"Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia",
"Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau",
"Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan",
"Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname",
"Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand",
"Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan",
"Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela",
"Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa",
"Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey",
"Saint Barthelemy","Saint Martin"};
QString GeoIPManager::CountryISOCodeToName(const QString &iso) {
if (iso.isEmpty()) return "N/A";
for (uint i = 0; i < num_countries; ++i) {
if (iso == country_code[i]) {
return QLatin1String(country_name[i]);
}
}
qDebug("GeoIPManager: Country name resolution failed for: %s", qPrintable(iso));
return "N/A";
}
// http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm
QIcon GeoIPManager::CountryISOCodeToIcon(const QString &iso) {
if (iso.isEmpty() || (iso[0] == '!')) return QIcon();
return QIcon(":/icons/flags/" + iso.toLower() + ".png");
}

1
src/gui/gui.pri

@ -3,7 +3,6 @@ INCLUDEPATH += $$PWD
include(lineedit/lineedit.pri) include(lineedit/lineedit.pri)
include(properties/properties.pri) include(properties/properties.pri)
include(rss/rss.pri) include(rss/rss.pri)
include(geoip/geoip.pri)
include(powermanagement/powermanagement.pri) include(powermanagement/powermanagement.pri)
unix:!macx:dbus: include(qtnotify/qtnotify.pri) unix:!macx:dbus: include(qtnotify/qtnotify.pri)

6
src/gui/guiiconprovider.cpp

@ -68,6 +68,12 @@ QIcon GuiIconProvider::getIcon(const QString &iconId)
return QIcon(IconProvider::getIconPath(iconId)); return QIcon(IconProvider::getIconPath(iconId));
} }
QIcon GuiIconProvider::getFlagIcon(const QString &countryIsoCode)
{
if (countryIsoCode.isEmpty()) return QIcon();
return QIcon(":/icons/flags/" + countryIsoCode.toLower() + ".png");
}
// Makes sure the icon is at least available in 16px and 24px size // Makes sure the icon is at least available in 16px and 24px size
// It scales the icon from the theme if necessary // It scales the icon from the theme if necessary
// Otherwise, the UI looks broken if the icon is not available // Otherwise, the UI looks broken if the icon is not available

1
src/gui/guiiconprovider.h

@ -44,6 +44,7 @@ public:
static GuiIconProvider *instance(); static GuiIconProvider *instance();
QIcon getIcon(const QString &iconId); QIcon getIcon(const QString &iconId);
QIcon getFlagIcon(const QString &countryIsoCode);
QString getIconPath(const QString &iconId); QString getIconPath(const QString &iconId);
private slots: private slots:

10
src/gui/properties/peerlistwidget.cpp

@ -42,7 +42,7 @@
#include "core/preferences.h" #include "core/preferences.h"
#include "core/logger.h" #include "core/logger.h"
#include "propertieswidget.h" #include "propertieswidget.h"
#include "geoipmanager.h" #include "core/net/geoipmanager.h"
#include "peersadditiondlg.h" #include "peersadditiondlg.h"
#include "speedlimitdlg.h" #include "speedlimitdlg.h"
#include "guiiconprovider.h" #include "guiiconprovider.h"
@ -303,10 +303,10 @@ QStandardItem* PeerListWidget::addPeer(const QString& ip, BitTorrent::TorrentHan
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PORT), peer.address().port); m_listModel->setData(m_listModel->index(row, PeerListDelegate::PORT), peer.address().port);
m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP_HIDDEN), ip); m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP_HIDDEN), ip);
if (m_displayFlags) { if (m_displayFlags) {
const QIcon ico = GeoIPManager::CountryISOCodeToIcon(peer.country()); const QIcon ico = GuiIconProvider::instance()->getFlagIcon(peer.country());
if (!ico.isNull()) { if (!ico.isNull()) {
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), ico, Qt::DecorationRole); m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), ico, Qt::DecorationRole);
const QString country_name = GeoIPManager::CountryISOCodeToName(peer.country()); const QString country_name = Net::GeoIPManager::CountryName(peer.country());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), country_name, Qt::ToolTipRole); m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), country_name, Qt::ToolTipRole);
} else { } else {
m_missingFlags.insert(ip); m_missingFlags.insert(ip);
@ -331,10 +331,10 @@ void PeerListWidget::updatePeer(const QString &ip, BitTorrent::TorrentHandle *co
QStandardItem *item = m_peerItems.value(ip); QStandardItem *item = m_peerItems.value(ip);
int row = item->row(); int row = item->row();
if (m_displayFlags) { if (m_displayFlags) {
const QIcon ico = GeoIPManager::CountryISOCodeToIcon(peer.country()); const QIcon ico = GuiIconProvider::instance()->getFlagIcon(peer.country());
if (!ico.isNull()) { if (!ico.isNull()) {
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), ico, Qt::DecorationRole); m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), ico, Qt::DecorationRole);
const QString country_name = GeoIPManager::CountryISOCodeToName(peer.country()); const QString country_name = Net::GeoIPManager::CountryName(peer.country());
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), country_name, Qt::ToolTipRole); m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), country_name, Qt::ToolTipRole);
m_missingFlags.remove(ip); m_missingFlags.remove(ip);
} }

7
unixconf.pri

@ -91,10 +91,3 @@ nogui:systemd {
# INSTALL # INSTALL
target.path = $$PREFIX/bin/ target.path = $$PREFIX/bin/
INSTALLS += target INSTALLS += target
!nogui {
# DEFINE added by configure
contains(DEFINES, WITH_GEOIP_EMBEDDED) {
message("You chose to embed GeoIP database in qBittorrent executable.")
}
}

4
winconf.pri

@ -32,7 +32,6 @@ DEFINES += _CRT_SECURE_NO_DEPRECATE
DEFINES += _SCL_SECURE_NO_DEPRECATE DEFINES += _SCL_SECURE_NO_DEPRECATE
DEFINES += __USE_W32_SOCKETS DEFINES += __USE_W32_SOCKETS
DEFINES += _FILE_OFFSET_BITS=64 DEFINES += _FILE_OFFSET_BITS=64
DEFINES += WITH_SHIPPED_GEOIP_H
CONFIG(debug, debug|release) { CONFIG(debug, debug|release) {
DEFINES += TORRENT_DEBUG DEFINES += TORRENT_DEBUG
@ -49,6 +48,3 @@ win32-g++ {
else { else {
include(winconf-msvc.pri) include(winconf-msvc.pri)
} }
DEFINES += WITH_GEOIP_EMBEDDED
message("On Windows, GeoIP database must be embedded.")

Loading…
Cancel
Save