Changeset View
Changeset View
Standalone View
Standalone View
ktorrent-5.1.1/plugins/infowidget/geoipmanager.cpp
1 | /*************************************************************************** | 1 | /*************************************************************************** | ||
---|---|---|---|---|---|
2 | * Copyright (C) 2009 by Joris Guisson * | 2 | * Copyright (C) 2009 by Joris Guisson * | ||
3 | * joris.guisson@gmail.com * | 3 | * joris.guisson@gmail.com * | ||
4 | * Copyright (C) 2019 by Bernhard "Bero" Rosenkraenzer <bero@lindev.ch> * | ||||
4 | * * | 5 | * * | ||
5 | * This program is free software; you can redistribute it and/or modify * | 6 | * This program is free software; you can redistribute it and/or modify * | ||
6 | * it under the terms of the GNU General Public License as published by * | 7 | * it under the terms of the GNU General Public License as published by * | ||
Context not available. | |||||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * | 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * | ||
19 | ***************************************************************************/ | 20 | ***************************************************************************/ | ||
20 | 21 | | |||
22 | #ifdef HAVE_MAXMINDDB | ||||
21 | #include <KIO/CopyJob> | 23 | #include <KIO/CopyJob> | ||
24 | #include <KTar> | ||||
25 | #endif | ||||
22 | 26 | | |||
23 | #include <QDateTime> | 27 | #include <QDateTime> | ||
24 | #include <QFile> | 28 | #include <QFile> | ||
25 | #include <QFileInfo> | 29 | #include <QFileInfo> | ||
26 | #include <QStandardPaths> | 30 | #include <QStandardPaths> | ||
31 | #include <QLocale> | ||||
27 | 32 | | |||
28 | #include <util/log.h> | 33 | #include <util/log.h> | ||
29 | #include <util/decompressfilejob.h> | 34 | #include <util/decompressfilejob.h> | ||
Context not available. | |||||
35 | 40 | | |||
36 | namespace kt | 41 | namespace kt | ||
37 | { | 42 | { | ||
38 | QUrl GeoIPManager::geoip_url = QUrl(QStringLiteral("http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz")); | 43 | #ifdef HAVE_MAXMINDDB | ||
44 | void UntarThread::run() { | ||||
45 | KTar tar(src); | ||||
46 | if(!tar.open(QIODevice::ReadOnly)) { | ||||
47 | Out(SYS_INW | LOG_IMPORTANT) << "Failed to open GeoIP database tarball" << endl; | ||||
48 | return; | ||||
49 | } | ||||
50 | scanDir(tar.directory()); | ||||
51 | tar.close(); | ||||
52 | QFile::remove(src); | ||||
53 | } | ||||
54 | | ||||
55 | void UntarThread::scanDir(const KArchiveDirectory *dir) { | ||||
56 | for(const QString &entry: dir->entries()) { | ||||
57 | if(dir->entry(entry)->isFile() && entry.endsWith(QFile::decodeName(".mmdb"))) { | ||||
58 | | ||||
59 | QFile f(dest); | ||||
60 | f.open(QFile::WriteOnly); | ||||
61 | f.write(dynamic_cast<const KArchiveFile*>(dir->entry(entry))->data()); | ||||
62 | f.close(); | ||||
63 | } else if(dir->entry(entry)->isDirectory()) { | ||||
64 | scanDir(dynamic_cast<const KArchiveDirectory*>(dir->entry(entry))); | ||||
65 | } | ||||
66 | } | ||||
67 | } | ||||
68 | | ||||
69 | QUrl GeoIPManager::geoip_url = QUrl(QStringLiteral("https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz")); | ||||
70 | #endif | ||||
39 | 71 | | |||
40 | GeoIPManager::GeoIPManager(QObject* parent): QObject(parent), geo_ip(nullptr), decompress_thread(nullptr) | 72 | GeoIPManager::GeoIPManager(QObject* parent): QObject(parent) | ||
73 | #ifdef HAVE_MAXMINDDB | ||||
74 | , untar_thread(nullptr) | ||||
75 | #endif | ||||
41 | { | 76 | { | ||
42 | #ifdef USE_SYSTEM_GEOIP | 77 | #ifdef HAVE_MAXMINDDB | ||
43 | geo_ip = GeoIP_open_type(GEOIP_COUNTRY_EDITION, GEOIP_STANDARD); | 78 | memset(&geo_ip, 0, sizeof(geo_ip)); | ||
44 | #else | 79 | geoip_data_file = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("GeoLite2-Country.mmdb")); | ||
45 | geoip_data_file = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("geoip.dat")); | | |||
46 | if (geoip_data_file.isEmpty()) | 80 | if (geoip_data_file.isEmpty()) | ||
47 | geoip_data_file = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("GeoIP.dat")); | 81 | geoip_data_file = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("geolite2-country.mmdb")); | ||
48 | 82 | | |||
49 | if (geoip_data_file.isEmpty()) | 83 | if (geoip_data_file.isEmpty()) | ||
50 | { | 84 | { | ||
Context not available. | |||||
52 | } | 86 | } | ||
53 | else | 87 | else | ||
54 | { | 88 | { | ||
55 | geo_ip = GeoIP_open(QFile::encodeName(geoip_data_file).data(), 0); | 89 | int status = MMDB_open(QFile::encodeName(geoip_data_file).data(), 0, &geo_ip); | ||
56 | if (geo_ip) | 90 | if (status == MMDB_SUCCESS) | ||
57 | { | 91 | { | ||
58 | QFileInfo fi(geoip_data_file); | 92 | QFileInfo fi(geoip_data_file); | ||
59 | QDateTime now = QDateTime::currentDateTime(); | 93 | QDateTime now = QDateTime::currentDateTime(); | ||
Context not available. | |||||
70 | 104 | | |||
71 | GeoIPManager::~GeoIPManager() | 105 | GeoIPManager::~GeoIPManager() | ||
72 | { | 106 | { | ||
73 | if (geo_ip) | 107 | #ifdef HAVE_MAXMINDDB | ||
74 | GeoIP_delete(geo_ip); | 108 | if (geo_ip.filename) | ||
109 | MMDB_close(&geo_ip); | ||||
75 | 110 | | |||
76 | if (decompress_thread) | 111 | if (untar_thread) | ||
77 | { | 112 | { | ||
78 | decompress_thread->cancel(); | 113 | untar_thread->wait(); | ||
79 | decompress_thread->wait(); | 114 | delete untar_thread; | ||
80 | delete decompress_thread; | | |||
81 | } | 115 | } | ||
116 | #endif | ||||
82 | } | 117 | } | ||
83 | 118 | | |||
84 | int GeoIPManager::findCountry(const QString& addr) | 119 | #ifndef HAVE_MAXMINDDB | ||
85 | { | 120 | static bool warnedAboutMissingMaxmindDB = false; | ||
86 | if (!geo_ip) | 121 | #endif | ||
87 | return 0; | | |||
88 | else | | |||
89 | return GeoIP_id_by_name(geo_ip, addr.toLatin1().data()); | | |||
90 | } | | |||
91 | 122 | | |||
92 | QString GeoIPManager::countryCode(int country_id) | 123 | QString GeoIPManager::findCountry(const QString& addr) | ||
93 | { | 124 | { | ||
94 | if (country_id > 0 && country_id < 247) | 125 | #ifdef HAVE_MAXMINDDB | ||
95 | return QString::fromLatin1(GeoIP_country_code[country_id]); | 126 | if (!geo_ip.filename) | ||
96 | else | 127 | return QString::null; | ||
97 | return QString(); | 128 | | ||
129 | int gai_error, mmdb_error, status; | ||||
130 | MMDB_lookup_result_s result = MMDB_lookup_string(&geo_ip, addr.toLatin1().data(), &gai_error, &mmdb_error); | ||||
131 | if (gai_error || mmdb_error != MMDB_SUCCESS || !result.found_entry) | ||||
132 | return QString::null; | ||||
133 | MMDB_entry_data_s entry_data; | ||||
134 | QString preferredLocale=QLocale::system().name().section(QChar::fromLatin1('_'), 0, 0); | ||||
135 | status = MMDB_get_value(&result.entry, &entry_data, "country", "names", preferredLocale.toLatin1().data(), nullptr); | ||||
136 | if (status != MMDB_SUCCESS || !entry_data.has_data || entry_data.type != MMDB_DATA_TYPE_UTF8_STRING) // Maxmind doesn't translate to every language -- fall back to English | ||||
137 | status = MMDB_get_value(&result.entry, &entry_data, "country", "names", "en", nullptr); | ||||
138 | if (status != MMDB_SUCCESS || !entry_data.has_data || entry_data.type != MMDB_DATA_TYPE_UTF8_STRING) | ||||
139 | return QString::null; | ||||
140 | char *country_utf8=strndup(entry_data.utf8_string, entry_data.data_size); | ||||
141 | QString country=QString::fromUtf8(country_utf8); | ||||
142 | free(country_utf8); | ||||
143 | return country; | ||||
144 | #else | ||||
145 | if (!warnedAboutMissingMaxmindDB) { | ||||
146 | Out(SYS_INW | LOG_NOTICE) << "Compiled without MaxMindDB support, country lookup not available." << endl; | ||||
147 | warnedAboutMissingMaxmindDB=true; | ||||
148 | } | ||||
149 | return QString::null; | ||||
150 | #endif | ||||
98 | } | 151 | } | ||
99 | 152 | | |||
100 | QString GeoIPManager::countryName(int country_id) | 153 | QString GeoIPManager::countryCode(const QString &addr) | ||
101 | { | 154 | { | ||
102 | if (country_id > 0 && country_id < 247) | 155 | #ifdef HAVE_MAXMINDDB | ||
103 | return QString::fromUtf8(GeoIP_country_name[country_id]); | 156 | if (!geo_ip.filename) | ||
104 | else | 157 | return QString::null; | ||
105 | return QString(); | 158 | | ||
159 | int gai_error, mmdb_error, status; | ||||
160 | MMDB_lookup_result_s result = MMDB_lookup_string(&geo_ip, addr.toLatin1().data(), &gai_error, &mmdb_error); | ||||
161 | if (gai_error || mmdb_error != MMDB_SUCCESS || !result.found_entry) | ||||
162 | return QString::null; | ||||
163 | MMDB_entry_data_s entry_data; | ||||
164 | status = MMDB_get_value(&result.entry, &entry_data, "country", "iso_code", nullptr); | ||||
165 | if (status != MMDB_SUCCESS || !entry_data.has_data || entry_data.type != MMDB_DATA_TYPE_UTF8_STRING) | ||||
166 | return QString::null; | ||||
167 | char *country_utf8=strndup(entry_data.utf8_string, entry_data.data_size); | ||||
168 | QString country=QString::fromUtf8(country_utf8); | ||||
169 | free(country_utf8); | ||||
170 | return country; | ||||
171 | #else | ||||
172 | if (!warnedAboutMissingMaxmindDB) { | ||||
173 | Out(SYS_INW | LOG_NOTICE) << "Compiled without MaxMindDB support, country lookup not available." << endl; | ||||
174 | warnedAboutMissingMaxmindDB=true; | ||||
175 | } | ||||
176 | return QString::null; | ||||
177 | #endif | ||||
106 | } | 178 | } | ||
107 | 179 | | |||
180 | #ifdef HAVE_MAXMINDDB | ||||
108 | void GeoIPManager::downloadDataBase() | 181 | void GeoIPManager::downloadDataBase() | ||
109 | { | 182 | { | ||
110 | #ifndef USE_SYSTEM_GEOIP | | |||
111 | Out(SYS_INW | LOG_NOTICE) << "Downloading GeoIP database: " << geoip_url << endl; | 183 | Out(SYS_INW | LOG_NOTICE) << "Downloading GeoIP database: " << geoip_url << endl; | ||
112 | download_destination = kt::DataDir(CreateIfNotExists) + geoip_url.fileName(); | 184 | download_destination = kt::DataDir(CreateIfNotExists) + geoip_url.fileName(); | ||
113 | KIO::CopyJob* job = KIO::copy(geoip_url, QUrl::fromLocalFile(download_destination), KIO::Overwrite | KIO::HideProgressInfo); | 185 | KIO::CopyJob* job = KIO::copy(geoip_url, QUrl::fromLocalFile(download_destination), KIO::Overwrite | KIO::HideProgressInfo); | ||
114 | connect(job, &KIO::CopyJob::result, this, &GeoIPManager::databaseDownloadFinished); | 186 | connect(job, &KIO::CopyJob::result, this, &GeoIPManager::databaseDownloadFinished); | ||
115 | #endif | | |||
116 | } | 187 | } | ||
117 | 188 | | |||
118 | void GeoIPManager::databaseDownloadFinished(KJob* job) | 189 | void GeoIPManager::databaseDownloadFinished(KJob* job) | ||
Context not available. | |||||
123 | return; | 194 | return; | ||
124 | } | 195 | } | ||
125 | 196 | | |||
126 | if (download_destination.endsWith(QLatin1String(".dat")) || download_destination.endsWith(QLatin1String(".DAT"))) | 197 | Out(SYS_INW | LOG_NOTICE) << "GeoIP database downloaded, decompressing ... " << endl; | ||
127 | { | 198 | // decompress the file | ||
128 | Out(SYS_INW | LOG_NOTICE) << "GeoIP database downloaded, opening ... " << endl; | 199 | untar_thread = new UntarThread(download_destination, kt::DataDir() + QLatin1String("GeoLite2-Country.mmdb")); | ||
129 | geoip_data_file = download_destination; | 200 | connect(untar_thread, &UntarThread::finished, this, &GeoIPManager::decompressFinished, Qt::QueuedConnection); | ||
130 | if (geo_ip) | 201 | untar_thread->start(QThread::IdlePriority); | ||
131 | { | | |||
132 | GeoIP_delete(geo_ip); | | |||
133 | geo_ip = nullptr; | | |||
134 | } | | |||
135 | geo_ip = GeoIP_open(QFile::encodeName(geoip_data_file).data(), 0); | | |||
136 | if (!geo_ip) | | |||
137 | Out(SYS_INW | LOG_NOTICE) << "Failed to open GeoIP database " << endl; | | |||
138 | } | | |||
139 | else | | |||
140 | { | | |||
141 | Out(SYS_INW | LOG_NOTICE) << "GeoIP database downloaded, decompressing ... " << endl; | | |||
142 | // decompress the file | | |||
143 | decompress_thread = new bt::DecompressThread(download_destination, kt::DataDir() + QLatin1String("geoip.dat")); | | |||
144 | connect(decompress_thread, &bt::DecompressThread::finished, this, &GeoIPManager::decompressFinished, Qt::QueuedConnection); | | |||
145 | decompress_thread->start(QThread::IdlePriority); | | |||
146 | } | | |||
147 | } | 202 | } | ||
148 | 203 | | |||
149 | void GeoIPManager::decompressFinished() | 204 | void GeoIPManager::decompressFinished() | ||
150 | { | 205 | { | ||
151 | Out(SYS_INW | LOG_NOTICE) << "GeoIP database decompressed, opening ... " << endl; | 206 | Out(SYS_INW | LOG_NOTICE) << "GeoIP database decompressed, opening ... " << endl; | ||
152 | if (!decompress_thread->error()) | 207 | geoip_data_file = kt::DataDir() + QLatin1String("GeoLite2-Country.mmdb"); | ||
208 | if (geo_ip.filename) | ||||
153 | { | 209 | { | ||
154 | geoip_data_file = kt::DataDir() + QLatin1String("geoip.dat"); | 210 | MMDB_close(&geo_ip); | ||
155 | if (geo_ip) | 211 | memset(&geo_ip, 0, sizeof(geo_ip)); | ||
156 | { | 212 | } | ||
157 | GeoIP_delete(geo_ip); | 213 | int status = MMDB_open(QFile::encodeName(geoip_data_file).data(), 0, &geo_ip); | ||
158 | geo_ip = nullptr; | 214 | if (status != MMDB_SUCCESS) { | ||
159 | } | 215 | Out(SYS_INW | LOG_NOTICE) << "Failed to open GeoIP database " << endl; | ||
160 | geo_ip = GeoIP_open(QFile::encodeName(geoip_data_file).data(), 0); | 216 | memset(&geo_ip, 0, sizeof(geo_ip)); | ||
161 | if (!geo_ip) | | |||
162 | Out(SYS_INW | LOG_NOTICE) << "Failed to open GeoIP database " << endl; | | |||
163 | } | 217 | } | ||
164 | 218 | | |||
165 | decompress_thread->wait(); | 219 | untar_thread->wait(); | ||
166 | delete decompress_thread; | 220 | delete untar_thread; | ||
167 | decompress_thread = nullptr; | 221 | untar_thread = nullptr; | ||
168 | } | 222 | } | ||
169 | 223 | | |||
170 | 224 | | |||
Context not available. | |||||
172 | { | 226 | { | ||
173 | geoip_url = url; | 227 | geoip_url = url; | ||
174 | } | 228 | } | ||
229 | #endif | ||||
175 | 230 | | |||
176 | /////////////////////////////////// | 231 | /////////////////////////////////// | ||
177 | 232 | | |||
Context not available. |