From 3146d2093e8cf429315df73402bd99cc6a2b628f Mon Sep 17 00:00:00 2001
From: Teo Mrnjavac <teo@kde.org>
Date: Thu, 18 Aug 2016 15:38:41 +0200
Subject: [PATCH] Add support for freegeoip.net in locale module.

This is disabled by default. To enable, provide a geoipUrl setting in
locale.conf.
Relies on the RequirementsChecker output, in the welcome module.
---
 src/modules/locale/LocaleViewStep.cpp | 116 ++++++++++++++++++++++----
 src/modules/locale/LocaleViewStep.h   |   9 +-
 2 files changed, 109 insertions(+), 16 deletions(-)

diff --git a/src/modules/locale/LocaleViewStep.cpp b/src/modules/locale/LocaleViewStep.cpp
index c2781f9b45..24719b1be6 100644
--- a/src/modules/locale/LocaleViewStep.cpp
+++ b/src/modules/locale/LocaleViewStep.cpp
@@ -1,6 +1,6 @@
 /* === This file is part of Calamares - <http://github.com/calamares> ===
  *
- *   Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
+ *   Copyright 2014-2016, Teo Mrnjavac <teo@kde.org>
  *
  *   Calamares is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -26,11 +26,16 @@
 
 #include "utils/CalamaresUtilsGui.h"
 #include "utils/Logger.h"
+#include "utils/YamlUtils.h"
 
 #include <QBoxLayout>
 #include <QLabel>
+#include <QNetworkRequest>
+#include <QNetworkReply>
 #include <QtConcurrent/QtConcurrentRun>
 
+#include <yaml-cpp/yaml.h>
+
 
 CALAMARES_PLUGIN_FACTORY_DEFINITION( LocaleViewStepFactory, registerPlugin<LocaleViewStep>(); )
 
@@ -44,25 +49,37 @@ LocaleViewStep::LocaleViewStep( QObject* parent )
     m_widget->setLayout( mainLayout );
     CalamaresUtils::unmarginLayout( mainLayout );
 
-    WaitingWidget* waitingWidget =
-        new WaitingWidget( tr( "Loading location data..." ) );
-
-    mainLayout->addWidget( waitingWidget );
+    m_waitingWidget = new WaitingWidget( tr( "Loading location data..." ) );
+    mainLayout->addWidget( m_waitingWidget );
 
     connect( &m_initWatcher, &QFutureWatcher< void >::finished,
-             [=]
+             this, [=]
     {
-        m_actualWidget->init( m_startingTimezone.first,
-                              m_startingTimezone.second,
-                              m_localeGenPath );
-        m_widget->layout()->removeWidget( waitingWidget );
-        waitingWidget->deleteLater();
-        m_widget->layout()->addWidget( m_actualWidget );
-        m_nextEnabled = true;
-        emit nextStatusChanged( m_nextEnabled );
+        bool hasInternet = Calamares::JobQueue::instance()->globalStorage()
+                           ->value( "hasInternet" ).toBool();
+        if ( m_geoipUrl.isEmpty() || !hasInternet )
+            setUpPage();
+        else
+            fetchGeoIpTimezone();
     });
 
-    QFuture< void > initFuture = QtConcurrent::run( LocaleGlobal::init );
+    QFuture< void > initFuture = QtConcurrent::run( [=]
+    {
+        LocaleGlobal::init();
+        if ( m_geoipUrl.isEmpty() )
+            return;
+
+        Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
+
+        // Max 10sec wait for RequirementsChecker to finish, assuming the welcome
+        // module is used.
+        // If welcome is not used, either "hasInternet" should be set by other means,
+        // or the GeoIP feature should be disabled.
+        for ( int i = 0; i < 10; ++i )
+            if ( !gs->contains( "hasInternet" ) )
+                QThread::sleep( 1 );
+    } );
+
     m_initWatcher.setFuture( initFuture );
 
     emit nextStatusChanged( m_nextEnabled );
@@ -76,6 +93,67 @@ LocaleViewStep::~LocaleViewStep()
 }
 
 
+void
+LocaleViewStep::setUpPage()
+{
+    m_actualWidget->init( m_startingTimezone.first,
+                          m_startingTimezone.second,
+                          m_localeGenPath );
+    m_widget->layout()->removeWidget( m_waitingWidget );
+    m_waitingWidget->deleteLater();
+    m_widget->layout()->addWidget( m_actualWidget );
+    m_nextEnabled = true;
+    emit nextStatusChanged( m_nextEnabled );
+}
+
+
+void
+LocaleViewStep::fetchGeoIpTimezone()
+{
+    QNetworkAccessManager *manager = new QNetworkAccessManager( this );
+    connect( manager, &QNetworkAccessManager::finished,
+            [=]( QNetworkReply* reply )
+    {
+        if ( reply->error() == QNetworkReply::NoError )
+        {
+            YAML::Node doc = YAML::Load( reply->readAll() );
+
+            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 timezone = timezoneString.split( '/', QString::SkipEmptyParts );
+                    if ( timezone.size() >= 2 )
+                    {
+                        cDebug() << "GeoIP reporting" << timezoneString;
+                        QString region = timezone.takeFirst();
+                        QString zone = timezone.join( '/' );
+                        m_startingTimezone = qMakePair( region, zone );
+                    }
+                }
+            }
+        }
+
+        reply->deleteLater();
+        manager->deleteLater();
+        setUpPage();
+    } );
+
+    QNetworkRequest request;
+    QString requestUrl = QString( "%1/json" )
+                         .arg( QUrl::fromUserInput( m_geoipUrl ).toString() );
+    request.setUrl( QUrl( requestUrl ) );
+    request.setAttribute( QNetworkRequest::FollowRedirectsAttribute, true );
+    manager->get( request );
+}
+
+
 QString
 LocaleViewStep::prettyName() const
 {
@@ -198,4 +276,12 @@ LocaleViewStep::setConfigurationMap( const QVariantMap& configurationMap )
     {
         m_localeGenPath = QStringLiteral( "/etc/locale.gen" );
     }
+
+    // Optional
+    if ( configurationMap.contains( "geoipUrl" ) &&
+         configurationMap.value( "geoipUrl" ).type() == QVariant::String &&
+         !configurationMap.value( "geoipUrl" ).toString().isEmpty() )
+    {
+        m_geoipUrl = configurationMap.value( "geoipUrl" ).toString();
+    }
 }
diff --git a/src/modules/locale/LocaleViewStep.h b/src/modules/locale/LocaleViewStep.h
index 1ab9c451e4..2785f3d4ab 100644
--- a/src/modules/locale/LocaleViewStep.h
+++ b/src/modules/locale/LocaleViewStep.h
@@ -1,6 +1,6 @@
 /* === This file is part of Calamares - <http://github.com/calamares> ===
  *
- *   Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
+ *   Copyright 2014-2016, Teo Mrnjavac <teo@kde.org>
  *
  *   Calamares is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -29,6 +29,7 @@
 #include <QFutureWatcher>
 
 class LocalePage;
+class WaitingWidget;
 
 class PLUGINDLLEXPORT LocaleViewStep : public Calamares::ViewStep
 {
@@ -59,9 +60,14 @@ public:
 
     void setConfigurationMap( const QVariantMap& configurationMap ) override;
 
+private slots:
+    void setUpPage();
+
 private:
+    void fetchGeoIpTimezone();
     QWidget* m_widget;
     QFutureWatcher< void > m_initWatcher;
+    WaitingWidget* m_waitingWidget;
 
     LocalePage* m_actualWidget;
     bool m_nextEnabled;
@@ -69,6 +75,7 @@ private:
 
     QPair< QString, QString > m_startingTimezone;
     QString m_localeGenPath;
+    QString m_geoipUrl;
 
     QList< Calamares::job_ptr > m_jobs;
 };
-- 
GitLab