You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

197 lines
6.8 KiB

/*
* Copyright (C) 2009 Petri Damstén <damu@iki.fi>
* - Original Implementation.
* 2009 Andrew Coles <andrew.coles@yahoo.co.uk>
* - Extension to iplocationtools engine.
* 2015 Martin Gräßlin <mgraesslin@kde.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, see <http://www.gnu.org/licenses/>.
*/
#include "location_ip.h"
#include <QDebug>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QUrl>
#include <KJob>
#include <KIO/Job>
#include <KIO/TransferJob>
#include <KSharedConfig>
#include <NetworkManagerQt/Manager>
#include <NetworkManagerQt/WirelessDevice>
class Ip::Private : public QObject {
Q_OBJECT
public:
Private(Ip *q) : q(q) {}
void readGeoLocation(KJob *job)
{
m_geoLocationResolved = true;
if (job && job->error()) {
qDebug() << "error" << job->errorString();
m_geoLocationPayload.clear();
checkUpdateData();
return;
}
const QJsonObject json = QJsonDocument::fromJson(m_geoLocationPayload).object();
m_geoLocationPayload.clear();
auto accuracyIt = json.find(QStringLiteral("accuracy"));
if (accuracyIt != json.end()) {
m_data[QStringLiteral("accuracy")] = (*accuracyIt).toDouble();
} else {
m_data[QStringLiteral("accuracy")] = 40000;
}
auto locationIt = json.find(QStringLiteral("location"));
if (locationIt != json.end()) {
QJsonObject location = (*locationIt).toObject();
m_data[QStringLiteral("latitude")] = location.value(QStringLiteral("lat")).toDouble();
m_data[QStringLiteral("longitude")] = location.value(QStringLiteral("lng")).toDouble();
}
checkUpdateData();
}
void clear() {
m_geoLocationPayload.clear();
m_countryPayload.clear();
m_countryResolved = false;
m_geoLocationResolved = false;
m_data.clear();
}
void geoLocationData(KIO::Job *job, const QByteArray &data) {
Q_UNUSED(job)
if (data.isEmpty()) {
return;
}
m_geoLocationPayload.append(data);
}
void countryData(KIO::Job *job, const QByteArray &data) {
Q_UNUSED(job)
if (data.isEmpty()) {
return;
}
m_countryPayload.append(data);
}
void readCountry(KJob *job) {
m_countryResolved = true;
if (job && job->error()) {
qDebug() << "error" << job->errorString();
m_countryPayload.clear();
checkUpdateData();
return;
}
const QJsonObject json = QJsonDocument::fromJson(m_countryPayload).object();
m_countryPayload.clear();
m_data[QStringLiteral("country")] = json.value(QStringLiteral("country_name")).toString();
m_data[QStringLiteral("country code")] = json.value(QStringLiteral("country_code")).toString();
checkUpdateData();
}
private:
void checkUpdateData() {
if (!m_countryResolved || !m_geoLocationResolved) {
return;
}
q->setData(m_data);
}
Ip *q;
QByteArray m_geoLocationPayload;
QByteArray m_countryPayload;
bool m_countryResolved = false;
bool m_geoLocationResolved = false;
Plasma::DataEngine::Data m_data;
};
Ip::Ip(QObject* parent, const QVariantList& args)
: GeolocationProvider(parent, args), d(new Private(this))
{
setUpdateTriggers(SourceEvent | NetworkConnected);
}
Ip::~Ip()
{
delete d;
}
static QJsonArray accessPoints()
{
QJsonArray wifiAccessPoints;
const KConfigGroup config = KSharedConfig::openConfig()->group(QStringLiteral("org.kde.plasma.geolocation.ip"));
if (!NetworkManager::isWirelessEnabled() || !config.readEntry("Wifi", false)) {
return wifiAccessPoints;
}
for (const auto &device : NetworkManager::networkInterfaces()) {
QSharedPointer<NetworkManager::WirelessDevice> wifi = qSharedPointerDynamicCast<NetworkManager::WirelessDevice>(device);
if (!wifi) {
continue;
}
for (const auto &network : wifi->networks()) {
const QString &ssid = network->ssid();
if (ssid.isEmpty() || ssid.endsWith(QLatin1String("_nomap"))) {
// skip hidden SSID and networks with "_nomap"
continue;
}
for (const auto &accessPoint : network->accessPoints()) {
wifiAccessPoints.append(QJsonObject{{QStringLiteral("macAddress"), accessPoint->hardwareAddress()}});
}
}
}
return wifiAccessPoints;
}
void Ip::update()
{
d->clear();
if (!NetworkManager::isNetworkingEnabled()) {
setData(Plasma::DataEngine::Data());
return;
}
const QJsonArray wifiAccessPoints = accessPoints();
QJsonObject request;
if (wifiAccessPoints.count() >= 2) {
request.insert(QStringLiteral("wifiAccessPoints"), wifiAccessPoints);
}
const QByteArray postData = QJsonDocument(request).toJson(QJsonDocument::Compact);
const QString apiKey = QStringLiteral("60e8eae6-3988-4ada-ad48-2cfddddf216b");
KIO::TransferJob *datajob = KIO::http_post(QUrl(QStringLiteral("https://location.services.mozilla.com/v1/geolocate?key=%1").arg(apiKey)),
postData,
KIO::HideProgressInfo);
datajob->addMetaData(QStringLiteral("content-type"), QStringLiteral("application/json"));
qDebug() << "Fetching https://location.services.mozilla.com/v1/geolocate";
connect(datajob, &KIO::TransferJob::data, d, &Ip::Private::geoLocationData);
connect(datajob, &KIO::TransferJob::result, d, &Ip::Private::readGeoLocation);
datajob = KIO::http_post(QUrl(QStringLiteral("https://location.services.mozilla.com/v1/country?key=%1").arg(apiKey)),
postData,
KIO::HideProgressInfo);
datajob->addMetaData(QStringLiteral("content-type"), QStringLiteral("application/json"));
connect(datajob, &KIO::TransferJob::data, d, &Ip::Private::countryData);
connect(datajob, &KIO::TransferJob::result, d, &Ip::Private::readCountry);
}
K_EXPORT_PLASMA_GEOLOCATIONPROVIDER(ip, Ip)
#include "location_ip.moc"