diff --git a/src/modules/locale/CMakeLists.txt b/src/modules/locale/CMakeLists.txt index e32f6e613..f35a9b4bd 100644 --- a/src/modules/locale/CMakeLists.txt +++ b/src/modules/locale/CMakeLists.txt @@ -4,6 +4,7 @@ calamares_add_plugin( locale TYPE viewmodule EXPORT_MACRO PLUGINDLLEXPORT_PRO SOURCES + GeoIPFreeGeoIP.cpp LCLocaleDialog.cpp LocaleConfiguration.cpp LocalePage.cpp diff --git a/src/modules/locale/GeoIP.h b/src/modules/locale/GeoIP.h new file mode 100644 index 000000000..e9e0fadfd --- /dev/null +++ b/src/modules/locale/GeoIP.h @@ -0,0 +1,61 @@ +/* === This file is part of Calamares - === + * + * Copyright 2018, Adriaan de Groot + * + * Calamares 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 3 of the License, or + * (at your option) any later version. + * + * Calamares 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 Calamares. If not, see . + */ + +#ifndef GEOIP_H +#define GEOIP_H + +#include +#include +#include + +class QNetworkReply; + +/** + * @brief Interface for GeoIP retrievers. + * + * A GeoIP retriever takes a configured URL (from the config file) + * and can handle the data returned from its interpretation of that + * configured URL, returning a region and zone. + */ +struct GeoIP +{ + using RegionZonePair = QPair; + + /** @brief Convert configured URL to a complete URL. + * + * Some GeoIP providers are configured with one URL, but actually + * do retrieval with another (e.g. when using the original + * implementation of FreeGeoIP, or when adding an API key). + */ + virtual QUrl fullUrl( const QString& configUrl ) = 0; + + /** @brief Handle a (successful) request by interpreting the data. + * + * Should return a ( , ) pair, e.g. + * ( "Europe", "Amsterdam" ). This is called **only** if the + * request to the fullUrl was successful; the handler + * is free to read as much, or as little, data as it + * likes. On error, returns a RegionZonePair with empty + * strings (e.g. ( "", "" ) ). + */ + virtual RegionZonePair processReply( QNetworkReply* ) = 0; + + virtual ~GeoIP(); // Defined in LocaleViewStep +} ; + +#endif diff --git a/src/modules/locale/GeoIPFreeGeoIP.cpp b/src/modules/locale/GeoIPFreeGeoIP.cpp new file mode 100644 index 000000000..be77dc2e4 --- /dev/null +++ b/src/modules/locale/GeoIPFreeGeoIP.cpp @@ -0,0 +1,74 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014-2016, Teo Mrnjavac + * Copyright 2018, Adriaan de Groot + * + * Calamares 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 3 of the License, or + * (at your option) any later version. + * + * Calamares 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 Calamares. If not, see . + */ + +#include "GeoIPFreeGeoIP.h" + +#include "utils/Logger.h" +#include "utils/YamlUtils.h" + +#include + +#include + +QUrl +FreeGeoIP::fullUrl( const QString& configUrl ) +{ + // FIXME: derpy way to append "/json" to the user-specified config URL + QString requestUrl = QString( "%1/json" ) + .arg( QUrl::fromUserInput( configUrl ).toString() ); + return QUrl( requestUrl ); +} + +GeoIP::RegionZonePair +FreeGeoIP::processReply( QNetworkReply* reply ) +{ + QByteArray data = reply->readAll(); + + try + { + YAML::Node doc = YAML::Load( data ); + + QVariant var = CalamaresUtils::yamlToVariant( doc ); + if ( !var.isNull() && + var.isValid() && + var.type() == QVariant::Map ) + { + QVariantMap map = var.toMap(); + if ( map.contains( "time_zone" ) && + !map.value( "time_zone" ).toString().isEmpty() ) + { + QString timezoneString = map.value( "time_zone" ).toString(); + QStringList tzParts = timezoneString.split( '/', QString::SkipEmptyParts ); + if ( tzParts.size() >= 2 ) + { + cDebug() << "GeoIP reporting" << timezoneString; + QString region = tzParts.takeFirst(); + QString zone = tzParts.join( '/' ); + return qMakePair( region, zone ); + } + } + } + } + catch ( YAML::Exception& e ) + { + CalamaresUtils::explainYamlException( e, data, "GeoIP data"); + } + + return qMakePair( QString(), QString() ); +} diff --git a/src/modules/locale/GeoIPFreeGeoIP.h b/src/modules/locale/GeoIPFreeGeoIP.h new file mode 100644 index 000000000..3fe6157a2 --- /dev/null +++ b/src/modules/locale/GeoIPFreeGeoIP.h @@ -0,0 +1,30 @@ +/* === This file is part of Calamares - === + * + * Copyright 2018, Adriaan de Groot + * + * Calamares 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 3 of the License, or + * (at your option) any later version. + * + * Calamares 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 Calamares. If not, see . + */ + +#ifndef GEOIPFREEGEOIP_H +#define GEOIPFREEGEOIP_H + +#include "GeoIP.h" + +struct FreeGeoIP : public GeoIP +{ + virtual QUrl fullUrl( const QString& configUrl ); + virtual RegionZonePair processReply( QNetworkReply* ); +} ; + +#endif diff --git a/src/modules/locale/LocaleViewStep.cpp b/src/modules/locale/LocaleViewStep.cpp index 73efc266f..d9f5d1338 100644 --- a/src/modules/locale/LocaleViewStep.cpp +++ b/src/modules/locale/LocaleViewStep.cpp @@ -1,6 +1,7 @@ /* === This file is part of Calamares - === * * Copyright 2014-2016, Teo Mrnjavac + * Copyright 2018, Adriaan de Groot * * Calamares is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,11 +19,14 @@ #include "LocaleViewStep.h" +#include "GeoIP.h" +#include "GeoIPFreeGeoIP.h" +#include "GlobalStorage.h" +#include "JobQueue.h" #include "LocalePage.h" + #include "timezonewidget/localeglobal.h" #include "widgets/WaitingWidget.h" -#include "JobQueue.h" -#include "GlobalStorage.h" #include "utils/CalamaresUtilsGui.h" #include "utils/Logger.h" @@ -111,53 +115,25 @@ void LocaleViewStep::fetchGeoIpTimezone() { QNetworkAccessManager *manager = new QNetworkAccessManager( this ); + GeoIP *handler = new FreeGeoIP; + connect( manager, &QNetworkAccessManager::finished, [=]( QNetworkReply* reply ) { if ( reply->error() == QNetworkReply::NoError ) { - QByteArray data = reply->readAll(); - - try - { - YAML::Node doc = YAML::Load( data ); - - QVariant var = CalamaresUtils::yamlToVariant( doc ); - if ( !var.isNull() && - var.isValid() && - var.type() == QVariant::Map ) - { - QVariantMap map = var.toMap(); - if ( map.contains( "time_zone" ) && - !map.value( "time_zone" ).toString().isEmpty() ) - { - QString timezoneString = map.value( "time_zone" ).toString(); - QStringList tzParts = timezoneString.split( '/', QString::SkipEmptyParts ); - if ( tzParts.size() >= 2 ) - { - cDebug() << "GeoIP reporting" << timezoneString; - QString region = tzParts.takeFirst(); - QString zone = tzParts.join( '/' ); - m_startingTimezone = qMakePair( region, zone ); - } - } - } - } - catch ( YAML::Exception& e ) - { - CalamaresUtils::explainYamlException( e, data, "GeoIP data"); - } + auto tz = handler->processReply( reply ); + if ( !tz.first.isEmpty() ) + m_startingTimezone = tz; } - + delete handler; reply->deleteLater(); manager->deleteLater(); setUpPage(); } ); QNetworkRequest request; - QString requestUrl = QString( "%1/json" ) - .arg( QUrl::fromUserInput( m_geoipUrl ).toString() ); - request.setUrl( QUrl( requestUrl ) ); + request.setUrl( handler->fullUrl( m_geoipUrl ) ); request.setAttribute( QNetworkRequest::FollowRedirectsAttribute, true ); manager->get( request ); } @@ -294,3 +270,9 @@ LocaleViewStep::setConfigurationMap( const QVariantMap& configurationMap ) m_geoipUrl = configurationMap.value( "geoipUrl" ).toString(); } } + + +// Defined here since the struct has nothing else in it +GeoIP::~GeoIP() +{ +}