diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index fa4265d6e..f7e249a54 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -23,6 +23,7 @@ set( libSources # GeoIP services geoip/Interface.cpp + geoip/GeoIPFixed.cpp geoip/GeoIPJSON.cpp geoip/Handler.cpp diff --git a/src/libcalamares/geoip/GeoIPFixed.cpp b/src/libcalamares/geoip/GeoIPFixed.cpp new file mode 100644 index 000000000..69d5d3a4e --- /dev/null +++ b/src/libcalamares/geoip/GeoIPFixed.cpp @@ -0,0 +1,47 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2020 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * License-Filename: LICENSE + */ + +#include "GeoIPFixed.h" + +namespace CalamaresUtils +{ +namespace GeoIP +{ + +GeoIPFixed::GeoIPFixed( const QString& attribute ) + : Interface( attribute.isEmpty() ? QStringLiteral( "Europe/Amsterdam" ) : attribute ) +{ +} + +QString +GeoIPFixed::rawReply( const QByteArray& ) +{ + return m_element; +} + +GeoIP::RegionZonePair +GeoIPFixed::processReply( const QByteArray& data ) +{ + return splitTZString( rawReply( data ) ); +} + +} // namespace GeoIP +} // namespace CalamaresUtils diff --git a/src/libcalamares/geoip/GeoIPFixed.h b/src/libcalamares/geoip/GeoIPFixed.h new file mode 100644 index 000000000..5d6fca266 --- /dev/null +++ b/src/libcalamares/geoip/GeoIPFixed.h @@ -0,0 +1,55 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2020 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * License-Filename: LICENSE + */ + +#ifndef GEOIP_GEOIPFIXED_H +#define GEOIP_GEOIPFIXED_H + +#include "Interface.h" + +namespace CalamaresUtils +{ +namespace GeoIP +{ +/** @brief GeoIP with a fixed return value + * + * The data is ignored entirely and the attribute value is returned unchanged. + * Note that you still need to provide a usable URL for a successful GeoIP + * lookup -- the URL's data is just ignored. + * + * @note This class is an implementation detail. + */ +class GeoIPFixed : public Interface +{ +public: + /** @brief Configure the value to return from rawReply() + * + * An empty string, which would not be a valid zone name, is + * translated to "Europe/Amsterdam". + */ + explicit GeoIPFixed( const QString& value = QString() ); + + virtual RegionZonePair processReply( const QByteArray& ) override; + virtual QString rawReply( const QByteArray& ) override; +}; + +} // namespace GeoIP +} // namespace CalamaresUtils +#endif diff --git a/src/libcalamares/geoip/GeoIPTests.cpp b/src/libcalamares/geoip/GeoIPTests.cpp index 4b1f8f8e1..7dd8c92b0 100644 --- a/src/libcalamares/geoip/GeoIPTests.cpp +++ b/src/libcalamares/geoip/GeoIPTests.cpp @@ -18,6 +18,7 @@ #include "GeoIPTests.h" +#include "GeoIPFixed.h" #include "GeoIPJSON.h" #ifdef QT_XML_LIB #include "GeoIPXML.h" @@ -240,3 +241,35 @@ GeoIPTests::testGet() CHECK_GET( XML, QString(), "https://geoip.kde.org/v1/ubiquity" ) // Temporary KDE service #endif } + +void +GeoIPTests::testFixed() +{ + { + GeoIPFixed f; + auto tz = f.processReply( QByteArray() ); + QCOMPARE( tz.first, QStringLiteral( "Europe" ) ); + QCOMPARE( tz.second, QStringLiteral( "Amsterdam" ) ); + + QCOMPARE( f.processReply( xml_data_ubiquity ), tz ); + QCOMPARE( f.processReply( QByteArray( "derp" ) ), tz ); + } + { + GeoIPFixed f( QStringLiteral( "America/Vancouver" ) ); + auto tz = f.processReply( QByteArray() ); + QCOMPARE( tz.first, QStringLiteral( "America" ) ); + QCOMPARE( tz.second, QStringLiteral( "Vancouver" ) ); + + QCOMPARE( f.processReply( xml_data_ubiquity ), tz ); + QCOMPARE( f.processReply( QByteArray( "derp" ) ), tz ); + } + { + GeoIPFixed f( QStringLiteral( "America/North Dakota/Beulah" ) ); + auto tz = f.processReply( QByteArray() ); + QCOMPARE( tz.first, QStringLiteral( "America" ) ); + QCOMPARE( tz.second, QStringLiteral( "North_Dakota/Beulah" ) ); + + QCOMPARE( f.processReply( xml_data_ubiquity ), tz ); + QCOMPARE( f.processReply( QByteArray( "derp" ) ), tz ); + } +} diff --git a/src/libcalamares/geoip/GeoIPTests.h b/src/libcalamares/geoip/GeoIPTests.h index a320e3263..45aae23e7 100644 --- a/src/libcalamares/geoip/GeoIPTests.h +++ b/src/libcalamares/geoip/GeoIPTests.h @@ -30,6 +30,7 @@ public: private Q_SLOTS: void initTestCase(); + void testFixed(); void testJSON(); void testJSONalt(); void testJSONbad(); diff --git a/src/libcalamares/geoip/Handler.cpp b/src/libcalamares/geoip/Handler.cpp index 99e55e926..ab7eea999 100644 --- a/src/libcalamares/geoip/Handler.cpp +++ b/src/libcalamares/geoip/Handler.cpp @@ -18,11 +18,13 @@ #include "Handler.h" +#include "GeoIPFixed.h" #include "GeoIPJSON.h" #if defined( QT_XML_LIB ) #include "GeoIPXML.h" #endif +#include "Settings.h" #include "network/Manager.h" #include "utils/Logger.h" #include "utils/NamedEnum.h" @@ -40,7 +42,8 @@ handlerTypes() static const NamedEnumTable names{ { QStringLiteral( "none" ), Type::None }, { QStringLiteral( "json" ), Type::JSON }, - { QStringLiteral( "xml" ), Type::XML } + { QStringLiteral( "xml" ), Type::XML }, + { QStringLiteral( "fixed" ), Type::Fixed } }; // *INDENT-ON* // clang-format on @@ -73,6 +76,10 @@ Handler::Handler( const QString& implementation, const QString& url, const QStri { cWarning() << "GeoIP style *none* does not do anything."; } + else if ( m_type == Type::Fixed && Calamares::Settings::instance() && !Calamares::Settings::instance()->debugMode() ) + { + cWarning() << "GeoIP style *fixed* is not recommended for production."; + } #if !defined( QT_XML_LIB ) else if ( m_type == Type::XML ) { @@ -99,6 +106,8 @@ create_interface( Handler::Type t, const QString& selector ) #else return nullptr; #endif + case Handler::Type::Fixed: + return std::make_unique< GeoIPFixed >( selector ); } NOTREACHED return nullptr; } diff --git a/src/libcalamares/geoip/Handler.h b/src/libcalamares/geoip/Handler.h index 518964caf..d15f7c710 100644 --- a/src/libcalamares/geoip/Handler.h +++ b/src/libcalamares/geoip/Handler.h @@ -43,9 +43,10 @@ class DLLEXPORT Handler public: enum class Type { - None, - JSON, - XML + None, // No lookup, returns empty string + JSON, // JSON-formatted data, returns extracted field + XML, // XML-formatted data, returns extracted field + Fixed // Returns selector string verbatim }; /** @brief An unconfigured handler; this always returns errors. */ diff --git a/src/libcalamares/geoip/Interface.h b/src/libcalamares/geoip/Interface.h index 1a9beaa41..78cc2392c 100644 --- a/src/libcalamares/geoip/Interface.h +++ b/src/libcalamares/geoip/Interface.h @@ -98,7 +98,7 @@ public: virtual QString rawReply( const QByteArray& ) = 0; protected: - Interface( const QString& e = QString() ); + Interface( const QString& element = QString() ); QString m_element; // string for selecting from data }; diff --git a/src/libcalamares/geoip/test_geoip.cpp b/src/libcalamares/geoip/test_geoip.cpp index 32c6f4e24..0587dda02 100644 --- a/src/libcalamares/geoip/test_geoip.cpp +++ b/src/libcalamares/geoip/test_geoip.cpp @@ -22,6 +22,7 @@ #include +#include "GeoIPFixed.h" #include "GeoIPJSON.h" #ifdef QT_XML_LIB #include "GeoIPXML.h" @@ -33,27 +34,34 @@ using namespace CalamaresUtils::GeoIP; int main( int argc, char** argv ) { - if ( argc != 2 ) + if ( ( argc != 2 ) && ( argc != 3 ) ) { - cerr << "Usage: curl url | test_geoip \n"; + cerr << "Usage: curl url | test_geoip [selector]\n"; return 1; } + QString format( argv[ 1 ] ); + QString selector = argc == 3 ? QString( argv[ 2 ] ) : QString(); + Interface* handler = nullptr; - if ( QStringLiteral( "json" ) == argv[ 1 ] ) + if ( QStringLiteral( "json" ) == format ) { - handler = new GeoIPJSON; + handler = new GeoIPJSON( selector ); } #ifdef QT_XML_LIB - else if ( QStringLiteral( "xml" ) == argv[ 1 ] ) + else if ( QStringLiteral( "xml" ) == format ) { - handler = new GeoIPXML; + handler = new GeoIPXML( selector ); } #endif + else if ( QStringLiteral( "fixed" ) == format ) + { + handler = new GeoIPFixed( selector ); + } if ( !handler ) { - cerr << "Unknown format '" << argv[ 1 ] << "'\n"; + cerr << "Unknown format '" << format.toLatin1().constData() << "'\n"; return 1; } diff --git a/src/modules/keyboard/Config.cpp b/src/modules/keyboard/Config.cpp index 8b651d05d..06f7b3e81 100644 --- a/src/modules/keyboard/Config.cpp +++ b/src/modules/keyboard/Config.cpp @@ -456,7 +456,7 @@ Config::onActivate() { "ar_YE", arabic }, { "ca_ES", "cat_ES" }, /* Catalan */ { "as_ES", "ast_ES" }, /* Asturian */ - { "en_CA", "eng_CA" }, /* Canadian English */ + { "en_CA", "us" }, /* Canadian English */ { "el_CY", "gr" }, /* Greek in Cyprus */ { "el_GR", "gr" }, /* Greek in Greeze */ { "ig_NG", "igbo_NG" }, /* Igbo in Nigeria */ diff --git a/src/modules/keyboard/KeyboardPage.cpp b/src/modules/keyboard/KeyboardPage.cpp index 21e55d5d0..43d116146 100644 --- a/src/modules/keyboard/KeyboardPage.cpp +++ b/src/modules/keyboard/KeyboardPage.cpp @@ -324,7 +324,7 @@ KeyboardPage::onActivate() { "ar_YE", arabic }, { "ca_ES", "cat_ES" }, /* Catalan */ { "as_ES", "ast_ES" }, /* Asturian */ - { "en_CA", "eng_CA" }, /* Canadian English */ + { "en_CA", "us" }, /* Canadian English */ { "el_CY", "gr" }, /* Greek in Cyprus */ { "el_GR", "gr" }, /* Greek in Greeze */ { "ig_NG", "igbo_NG" }, /* Igbo in Nigeria */ diff --git a/src/modules/locale/locale.conf b/src/modules/locale/locale.conf index 4beb4fe85..dc68a050f 100644 --- a/src/modules/locale/locale.conf +++ b/src/modules/locale/locale.conf @@ -30,14 +30,18 @@ zone: "New_York" # # GeoIP needs a working Internet connection. # This can be managed from `welcome.conf` by adding -# internet to the list of required conditions. +# internet to the list of required conditions. (The welcome +# module can also do its own GeoIP lookups, independently +# of the lookup done here. The lookup in the welcome module +# is used to establish language; this one is for timezone). # -# The configuration -# is in three parts: a *style*, which can be "json" or "xml" -# depending on the kind of data returned by the service, and -# a *url* where the data is retrieved, and an optional *selector* -# to pick the right field out of the returned data (e.g. field -# name in JSON or element name in XML). +# The configuration is in three parts: +# - a *style*, which can be "json" or "xml" depending on the +# kind of data returned by the service, and +# - a *url* where the data is retrieved, and +# - an optional *selector* +# to pick the right field out of the returned data (e.g. field +# name in JSON or element name in XML). # # The default selector (when the setting is blank) is picked to # work with existing JSON providers (which use "time_zone") and @@ -45,8 +49,8 @@ zone: "New_York" # # If the service configured via *url* uses # a different attribute name (e.g. "timezone") in JSON or a -# different element tag (e.g. "") in XML, set this -# string to the name or tag to be used. +# different element tag (e.g. "") in XML, set the +# selector to the name or tag to be used. # # In JSON: # - if the string contains "." characters, this is used as a @@ -58,7 +62,10 @@ zone: "New_York" # - all elements with the named tag (e.g. all TimeZone) elements # from the document are checked; the first one with non-empty # text value is used. -# +# Special case: +# - the *style* "fixed" is also supported. This ignores the data +# returned from the URL (but the URL must still be valid!) +# and just returns the value of the *selector*. # # An HTTP(S) request is made to *url*. The request should return # valid data in a suitable format, depending on *style*; @@ -67,9 +74,6 @@ zone: "New_York" # does not follow the conventions of "suitable data" described # below, *selector* may be used to pick different data. # -# Note that this example URL works, but the service is shutting -# down in June 2018. -# # Suitable JSON data looks like # ``` # {"time_zone":"America/New_York"} @@ -84,9 +88,6 @@ zone: "New_York" # - backslashes are removed # - spaces are replaced with _ # -# Legacy settings "geoipStyle", "geoipUrl" and "geoipSelector" -# in the top-level are still supported, but I'd advise against. -# # To disable GeoIP checking, either comment-out the entire geoip section, # or set the *style* key to an unsupported format (e.g. `none`). # Also, note the analogous feature in src/modules/welcome/welcome.conf. @@ -95,3 +96,12 @@ geoip: style: "json" url: "https://geoip.kde.org/v1/calamares" selector: "" # leave blank for the default + +# For testing purposes, you could use *fixed* style, to see how Calamares +# behaves in a particular zone: +# +# geoip: +# style: "fixed" +# url: "https://geoip.kde.org/v1/calamares" # Still needs to be valid! +# selector: "America/Vancouver" # this is the selected zone +# diff --git a/src/modules/welcome/welcome.conf b/src/modules/welcome/welcome.conf index 224bc6ded..d8da60d19 100644 --- a/src/modules/welcome/welcome.conf +++ b/src/modules/welcome/welcome.conf @@ -64,7 +64,8 @@ requirements: # # To disable GeoIP checking, either comment-out the entire geoip section, # or set the *style* key to an unsupported format (e.g. `none`). -# Also, note the analogous feature in src/modules/locale/locale.conf. +# Also, note the analogous feature in `src/modules/locale/locale.conf`, +# which is where you will find complete documentation. # geoip: style: "none"