[PATCH 5/9] Let NetworkManager read oFono settings file and create connections



From: Mathieu Trudel-Lapierre <mathieu trudel-lapierre canonical com>

Gbp-Pq: Name Let-NetworkManager-read-oFono-settings-file-and-crea.patch
---
 configure.ac                                     |   6 +
 src/settings/plugins/Makefile.am                 |   5 +
 src/settings/plugins/ofono/Makefile.am           |  34 +
 src/settings/plugins/ofono/nm-ofono-connection.c | 169 +++++
 src/settings/plugins/ofono/nm-ofono-connection.h |  54 ++
 src/settings/plugins/ofono/parser.c              | 121 ++++
 src/settings/plugins/ofono/parser.h              |  36 ++
 src/settings/plugins/ofono/plugin.c              | 789 +++++++++++++++++++++++
 src/settings/plugins/ofono/plugin.h              |  53 ++
 9 files changed, 1267 insertions(+)
 create mode 100644 src/settings/plugins/ofono/Makefile.am
 create mode 100644 src/settings/plugins/ofono/nm-ofono-connection.c
 create mode 100644 src/settings/plugins/ofono/nm-ofono-connection.h
 create mode 100644 src/settings/plugins/ofono/parser.c
 create mode 100644 src/settings/plugins/ofono/parser.h
 create mode 100644 src/settings/plugins/ofono/plugin.c
 create mode 100644 src/settings/plugins/ofono/plugin.h

diff --git a/configure.ac b/configure.ac
index b7a0583..2ccfa23 100644
--- a/configure.ac
+++ b/configure.ac
@@ -95,6 +95,7 @@ AC_ARG_ENABLE(ifcfg-rh, AS_HELP_STRING([--enable-ifcfg-rh], [enable ifcfg-rh con
 AC_ARG_ENABLE(ifcfg-suse, AS_HELP_STRING([--enable-ifcfg-suse], [enable ifcfg-suse configuration plugin 
(SUSE) (deprecated)]))
 AC_ARG_ENABLE(ifupdown, AS_HELP_STRING([--enable-ifupdown], [enable ifupdown configuration plugin 
(Debian/Ubuntu)]))
 AC_ARG_ENABLE(ifnet, AS_HELP_STRING([--enable-ifnet], [enable ifnet configuration plugin (Gentoo)]))
+AC_ARG_ENABLE(ofono, AS_HELP_STRING([--enable-ofono], [enable ofono configuration plugin (Ubuntu)]))
 # Default alternative plugins by distribution
 AS_IF([test -z "$enable_ifcfg_rh"], AC_CHECK_FILE(/etc/redhat-release, enable_ifcfg_rh=yes))
 AS_IF([test -z "$enable_ifcfg_rh"], AC_CHECK_FILE(/etc/fedora-release, enable_ifcfg_rh=yes))
@@ -102,6 +103,8 @@ AS_IF([test -z "$enable_ifcfg_rh"], AC_CHECK_FILE(/etc/mandriva-release, enable_
 AS_IF([test -z "$enable_ifcfg_suse"], AC_CHECK_FILE(/etc/SuSE-release, enable_ifcfg_suse=yes))
 AS_IF([test -z "$enable_ifupdown"], AC_CHECK_FILE(/etc/debian_version, enable_ifupdown=yes))
 AS_IF([test -z "$enable_ifnet"], AC_CHECK_FILE(/etc/gentoo-release, enable_ifnet=yes))
+# Ofono is always enabled.
+AS_IF([test -z "$enable_ofono"], enable_ofono=yes)
 # Otherwise plugins default to "no"
 AS_IF([test -z "$enable_ifcfg_rh"], enable_ifcfg_rh=no)
 AS_IF([test -z "$enable_ifcfg_suse"], enable_ifcfg_suse=no)
@@ -114,6 +117,7 @@ AM_CONDITIONAL(CONFIG_PLUGIN_IBFT, test "$enable_config_plugin_ibft" = "yes")
 AM_CONDITIONAL(CONFIG_PLUGIN_IFCFG_RH, test "$enable_ifcfg_rh" = "yes")
 AM_CONDITIONAL(CONFIG_PLUGIN_IFUPDOWN, test "$enable_ifupdown" = "yes")
 AM_CONDITIONAL(CONFIG_PLUGIN_IFNET, test "$enable_ifnet" = "yes")
+AM_CONDITIONAL(CONFIG_PLUGIN_OFONO, test "$enable_ofono" = "yes")
 
 AC_ARG_WITH(config-plugins-default, AS_HELP_STRING([--with-config-plugins-default=PLUGINS], [Default 
configuration option for main.plugins setting, used as fallback if the configuration option is unset]), 
[config_plugins_default="$withval"], [config_plugins_default=""])
 if test -z "$config_plugins_default" -o "$config_plugins_default" = no; then
@@ -1043,6 +1047,7 @@ src/ppp-manager/Makefile
 src/settings/plugins/Makefile
 src/settings/plugins/ifupdown/Makefile
 src/settings/plugins/ifupdown/tests/Makefile
+src/settings/plugins/ofono/Makefile
 src/settings/plugins/ifnet/Makefile
 src/settings/plugins/ifnet/tests/Makefile
 src/settings/plugins/ifcfg-rh/Makefile
@@ -1169,6 +1174,7 @@ echo "  ibft: ${enable_config_plugin_ibft}"
 echo "  ifcfg-rh: ${enable_ifcfg_rh}"
 echo "  ifupdown: ${enable_ifupdown}"
 echo "  ifnet: ${enable_ifnet}"
+echo "  ofono: ${enable_ofono}"
 echo
 
 echo "Handlers for /etc/resolv.conf:"
diff --git a/src/settings/plugins/Makefile.am b/src/settings/plugins/Makefile.am
index 278d455..dcd3f20 100644
--- a/src/settings/plugins/Makefile.am
+++ b/src/settings/plugins/Makefile.am
@@ -17,3 +17,8 @@ endif
 if CONFIG_PLUGIN_IFNET
 SUBDIRS+=ifnet
 endif
+
+if CONFIG_PLUGIN_OFONO
+SUBDIRS+=ofono
+endif
+
diff --git a/src/settings/plugins/ofono/Makefile.am b/src/settings/plugins/ofono/Makefile.am
new file mode 100644
index 0000000..a9b2941
--- /dev/null
+++ b/src/settings/plugins/ofono/Makefile.am
@@ -0,0 +1,34 @@
+SUBDIRS = .
+
+ GNOME_CODE_COVERAGE_RULES@
+
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/src \
+       -I$(top_srcdir)/src/settings \
+       -I$(top_srcdir)/shared \
+       -I$(top_builddir)/shared \
+       -I$(top_srcdir)/libnm-core \
+       -I$(top_builddir)/libnm-core \
+       -DG_LOG_DOMAIN=\""NetworkManager-ifupdown"\" \
+       -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \
+       -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+       $(GLIB_CFLAGS) \
+       $(GUDEV_CFLAGS) \
+       -DSYSCONFDIR=\"$(sysconfdir)\"
+
+noinst_LTLIBRARIES = libofono-io.la
+
+libofono_io_la_SOURCES = \
+       parser.c \
+       parser.h
+
+pkglib_LTLIBRARIES = libnm-settings-plugin-ofono.la
+
+libnm_settings_plugin_ofono_la_SOURCES = \
+       nm-ofono-connection.c \
+       nm-ofono-connection.h \
+       plugin.c \
+       plugin.h
+
+libnm_settings_plugin_ofono_la_LDFLAGS = -module -avoid-version
+libnm_settings_plugin_ofono_la_LIBADD = libofono-io.la
diff --git a/src/settings/plugins/ofono/nm-ofono-connection.c 
b/src/settings/plugins/ofono/nm-ofono-connection.c
new file mode 100644
index 0000000..5ddcc02
--- /dev/null
+++ b/src/settings/plugins/ofono/nm-ofono-connection.c
@@ -0,0 +1,169 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
+/* NetworkManager system settings service (ofono)
+ *
+ * Mathieu Trudel-Lapierre <mathieu-tl ubuntu com>
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2013 Canonical Ltd.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib/gstdio.h>
+
+#include <nm-dbus-interface.h>
+#include <nm-utils.h>
+#include <nm-setting-wireless-security.h>
+#include <nm-settings-connection.h>
+#include <nm-settings-plugin.h>
+
+#include "nm-ofono-connection.h"
+#include "parser.h"
+
+G_DEFINE_TYPE (NMOfonoConnection, nm_ofono_connection, NM_TYPE_SETTINGS_CONNECTION)
+
+#define NM_OFONO_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_OFONO_CONNECTION, 
NMOfonoConnectionPrivate))
+
+typedef struct {
+       GHashTable *context;
+} NMOfonoConnectionPrivate;
+
+enum {
+       PROP_ZERO,
+       PROP_CONTEXT,
+       _PROP_END,
+};
+
+
+NMOfonoConnection*
+nm_ofono_connection_new (GHashTable *context)
+{
+       g_return_val_if_fail (context != NULL, NULL);
+
+       return (NMOfonoConnection *) g_object_new (NM_TYPE_OFONO_CONNECTION,
+                                                  NM_OFONO_CONNECTION_CONTEXT, context,
+                                                  NULL);
+}
+
+static gboolean
+supports_secrets (NMSettingsConnection *connection, const char *setting_name)
+{
+       return FALSE;
+}
+
+static void
+nm_ofono_connection_init (NMOfonoConnection *connection)
+{
+}
+
+static GObject *
+constructor (GType type,
+                  guint n_construct_params,
+                  GObjectConstructParam *construct_params)
+{
+       GObject *object;
+       NMOfonoConnectionPrivate *priv;
+       GError *error = NULL;
+
+       object = G_OBJECT_CLASS (nm_ofono_connection_parent_class)->constructor (type, n_construct_params, 
construct_params);
+       g_return_val_if_fail (object, NULL);
+
+       priv = NM_OFONO_CONNECTION_GET_PRIVATE (object);
+       if (!priv) {
+               g_warning ("%s.%d - no private instance.", __FILE__, __LINE__);
+               goto err;
+       }
+       if (!priv->context) {
+               g_warning ("(ofono) context not provided to constructor.");
+               goto err;
+       }
+
+       if (!ofono_update_connection_from_context (NM_CONNECTION (object), priv->context, &error)) {
+               g_warning ("%s.%d - invalid connection read from Ofono: (%d) %s",
+                          __FILE__,
+                          __LINE__,
+                          error ? error->code : -1,
+                          error && error->message ? error->message : "(unknown)");
+               goto err;
+       }
+
+       return object;
+
+ err:
+       g_object_unref (object);
+       return NULL;
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+                   const GValue *value, GParamSpec *pspec)
+{
+       NMOfonoConnectionPrivate *priv = NM_OFONO_CONNECTION_GET_PRIVATE (object);
+       g_return_if_fail (priv);
+
+       switch (prop_id) {
+       case PROP_CONTEXT:
+               priv->context = g_value_get_pointer (value);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+                   GValue *value, GParamSpec *pspec)
+{
+       NMOfonoConnectionPrivate *priv = NM_OFONO_CONNECTION_GET_PRIVATE (object);
+       g_return_if_fail (priv);
+
+       switch (prop_id) {
+       case PROP_CONTEXT:
+               g_value_set_pointer (value, priv->context);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+nm_ofono_connection_class_init (NMOfonoConnectionClass *ofono_connection_class)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (ofono_connection_class);
+       NMSettingsConnectionClass *connection_class = NM_SETTINGS_CONNECTION_CLASS (ofono_connection_class);
+
+       g_type_class_add_private (ofono_connection_class, sizeof (NMOfonoConnectionPrivate));
+
+       /* Virtual methods */
+       object_class->constructor  = constructor;
+       object_class->set_property = set_property;
+       object_class->get_property = get_property;
+
+       connection_class->supports_secrets = supports_secrets;
+
+       /* Properties */
+       g_object_class_install_property
+               (object_class, PROP_CONTEXT,
+                g_param_spec_pointer (NM_OFONO_CONNECTION_CONTEXT,
+                                                  "context",
+                                                  "",
+                                                  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
diff --git a/src/settings/plugins/ofono/nm-ofono-connection.h 
b/src/settings/plugins/ofono/nm-ofono-connection.h
new file mode 100644
index 0000000..e7deb5b
--- /dev/null
+++ b/src/settings/plugins/ofono/nm-ofono-connection.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
+/* NetworkManager system settings service (ofono)
+ *
+ * Mathieu Trudel-Lapierre <mathieu-tl ubuntu com>
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2013 Canonical Ltd.
+ */
+
+#ifndef NM_OFONO_CONNECTION_H
+#define NM_OFONO_CONNECTION_H
+
+#include <nm-settings-connection.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_OFONO_CONNECTION            (nm_ofono_connection_get_type ())
+#define NM_OFONO_CONNECTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_OFONO_CONNECTION, 
NMOfonoConnection))
+#define NM_OFONO_CONNECTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_OFONO_CONNECTION, 
NMOfonoConnectionClass))
+#define NM_IS_OFONO_CONNECTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_OFONO_CONNECTION))
+#define NM_IS_OFONO_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_OFONO_CONNECTION))
+#define NM_OFONO_CONNECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_OFONO_CONNECTION, 
NMOfonoConnectionClass))
+
+#define NM_OFONO_CONNECTION_CONTEXT "context"
+
+typedef struct {
+       NMSettingsConnection parent;
+} NMOfonoConnection;
+
+typedef struct {
+       NMSettingsConnectionClass parent;
+} NMOfonoConnectionClass;
+
+GType nm_ofono_connection_get_type (void);
+
+NMOfonoConnection *nm_ofono_connection_new (GHashTable *context);
+
+G_END_DECLS
+
+#endif /* NM_OFONO_CONNECTION_H */
diff --git a/src/settings/plugins/ofono/parser.c b/src/settings/plugins/ofono/parser.c
new file mode 100644
index 0000000..1c65b9b
--- /dev/null
+++ b/src/settings/plugins/ofono/parser.c
@@ -0,0 +1,121 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
+/* NetworkManager system settings service (ofono)
+ *
+ * Mathieu Trudel-Lapierre <mathieu-tl ubuntu com>
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2013 Canonical Ltd.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "nm-core-internal.h"
+#include "nm-settings-plugin.h"
+#include "nm-default.h"
+
+#include "parser.h"
+#include "plugin.h"
+
+#include <nm-setting-connection.h>
+#include <nm-setting-ip4-config.h>
+#include <nm-setting-ip6-config.h>
+#include <nm-setting-ppp.h>
+#include <nm-setting-wired.h>
+#include <nm-setting-wireless.h>
+#include <nm-setting-8021x.h>
+#include <nm-utils.h>
+#include <nm-logging.h>
+#include <ctype.h>
+
+gboolean
+ofono_update_connection_from_context (NMConnection *connection,
+                                      GHashTable *context,
+                                      GError **error)
+{
+       NMSettingConnection *s_con;
+       NMSettingGsm *s_gsm;
+       NMSettingIP6Config *s_ip6_config;
+       gboolean success = FALSE;
+       char *idstr = NULL;
+       char *uuid_base = NULL;
+       char *uuid = NULL;
+
+       s_con = nm_connection_get_setting_connection (connection);
+       if(!s_con) {
+               s_con = NM_SETTING_CONNECTION (nm_setting_connection_new());
+               g_assert (s_con);
+               nm_connection_add_setting (connection, NM_SETTING (s_con));
+       }
+
+       idstr = g_strconcat ("/",
+                            g_hash_table_lookup (context, "IMSI"),
+                            "/",
+                            g_hash_table_lookup (context, "ID"),
+                            NULL);
+       uuid_base = idstr;
+
+       uuid = nm_utils_uuid_generate_from_string (uuid_base, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL);
+       g_object_set (s_con,
+                     NM_SETTING_CONNECTION_TYPE, NM_SETTING_GSM_SETTING_NAME,
+                     NM_SETTING_CONNECTION_ID, idstr,
+                     NM_SETTING_CONNECTION_UUID, uuid,
+                     NM_SETTING_CONNECTION_READ_ONLY, TRUE,
+                     NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
+                     NULL);
+       g_free (uuid);
+
+       /* GSM setting */
+       s_gsm = NM_SETTING_GSM (nm_setting_gsm_new ());
+       g_assert (s_gsm);
+       nm_connection_add_setting (connection, NM_SETTING (s_gsm));
+
+       /*
+        * oFono should already know how to handle placing the call, but NM
+        * insists on having a number. Pass the usual *99#.
+        */
+       g_object_set (s_gsm, NM_SETTING_GSM_NUMBER, "*99#", NULL);
+
+       /* IP6 setting */
+       s_ip6_config = NM_SETTING_IP6_CONFIG (nm_setting_ip6_config_new());
+       g_assert (s_ip6_config);
+       nm_connection_add_setting (connection, NM_SETTING (s_ip6_config));
+
+       /*
+        * Set IP6_CONFIG_METHOD to ignore to prevent NM from configuring IPv6
+        * for ofono connections.
+        */
+       g_object_set (s_ip6_config,
+                           "method",
+                           NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
+                           NULL);
+
+       nm_log_info (LOGD_SETTINGS, "SCPlugin-Ofono: "
+                    "update_connection_setting_from_context: name:%s, path:%s, id:%s, uuid: %s",
+                    (char *) g_hash_table_lookup (context, "Name"),
+                    (char *) g_hash_table_lookup (context, "ID"),
+                    idstr, nm_setting_connection_get_uuid (s_con));
+
+       success = nm_connection_verify (connection, error);
+
+       g_free (idstr);
+       return success;
+}
diff --git a/src/settings/plugins/ofono/parser.h b/src/settings/plugins/ofono/parser.h
new file mode 100644
index 0000000..1ef1d20
--- /dev/null
+++ b/src/settings/plugins/ofono/parser.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
+/* NetworkManager system settings service (ofono)
+ *
+ * Mathieu Trudel-Lapierre <mathieu-tl ubuntu com>
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2013 Canonical Ltd.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <nm-connection.h>
+
+G_BEGIN_DECLS
+
+gboolean
+ofono_update_connection_from_context (NMConnection *connection,
+                                      GHashTable *context,
+                                      GError **error);
+
+G_END_DECLS
diff --git a/src/settings/plugins/ofono/plugin.c b/src/settings/plugins/ofono/plugin.c
new file mode 100644
index 0000000..08df730
--- /dev/null
+++ b/src/settings/plugins/ofono/plugin.c
@@ -0,0 +1,789 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/* Ofono modem settings service
+ *
+ * Mathieu Trudel-Lapierre <mathieu-tl ubuntu com>
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2013 - 2016 Canonical Ltd.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gmodule.h>
+
+#include "nm-dbus-interface.h"
+#include "nm-settings-plugin.h"
+#include "nm-setting-ip4-config.h"
+#include "nm-setting-wireless.h"
+#include "nm-setting-wired.h"
+#include "nm-setting-ppp.h"
+#include "nm-utils.h"
+#include "nm-core-internal.h"
+#include "NetworkManagerUtils.h"
+
+#include "nm-ofono-connection.h"
+#include "plugin.h"
+#include "parser.h"
+#include "nm-inotify-helper.h"
+
+#include "nm-logging.h"
+
+#define OFONO_CONFIG_DIR "/var/lib/ofono"
+#define OFONO_PLUGIN_NAME "ofono"
+#define OFONO_PLUGIN_INFO "(C) 2013-2016 Canonical Ltd.  To report bugs please use the NetworkManager 
mailing list."
+
+#define OFONO_KEY_FILE_GROUP "settings"
+
+typedef struct {
+       GHashTable *connections;  /* NMOfonoConnection */
+
+       GFileMonitor *ofono_dir_monitor;
+       gulong ofono_dir_monitor_id;
+
+       GHashTable *ofono_imsi_monitors;
+       GHashTable *ofono_imsi_monitor_ids;
+} SettingsPluginOfonoPrivate;
+
+
+static gboolean nm_ofono_read_imsi_contexts (SettingsPluginOfono *self,
+                                             const char *imsi,
+                                             GError **error);
+static void
+settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface);
+
+G_DEFINE_TYPE_EXTENDED (SettingsPluginOfono, settings_plugin_ofono, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN,
+                                               settings_plugin_interface_init))
+
+#define SETTINGS_PLUGIN_OFONO_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SETTINGS_TYPE_PLUGIN_OFONO, 
SettingsPluginOfonoPrivate))
+
+GQuark
+ofono_plugin_error_quark (void)
+{
+        static GQuark error_quark = 0;
+
+       if (!error_quark) {
+               error_quark = g_quark_from_static_string ("ofono-plugin-error-quark");
+       }
+
+       return error_quark;
+}
+
+static void
+SettingsPluginOfono_parse_contexts (SettingsPluginOfono *self, GSList *contexts, const char *imsi)
+{
+       SettingsPluginOfonoPrivate *priv = SETTINGS_PLUGIN_OFONO_GET_PRIVATE (self);
+       GSList *list;
+       NMOfonoConnection *exported;
+       gboolean found = FALSE;
+       char *uuid;
+       GHashTableIter iter;
+       gpointer key;
+       GHashTable *uuids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+       for (list = contexts; list; list = list->next) {
+               GHashTable *context = (GHashTable *) list->data;
+               const char *id, *name;
+               char *idstr;
+
+               id = g_hash_table_lookup (context, "ID");
+               name = g_hash_table_lookup (context, "Name");
+
+               idstr = g_strconcat ("/", imsi, "/", id, NULL);
+               uuid = nm_utils_uuid_generate_from_string (idstr, -1,
+                                                          NM_UTILS_UUID_TYPE_LEGACY,
+                                                          NULL);
+               g_free (idstr);
+
+               g_hash_table_insert (uuids, g_strdup (uuid), NULL);
+
+               nm_log_info (LOGD_SETTINGS, "SettingsPlugin-Ofono: found internet context '%s' (%s)",
+                            name, id);
+
+               /* Ignore any connection for this block that was previously found */
+               exported = g_hash_table_lookup (priv->connections, uuid);
+               if (exported) {
+                       nm_log_info (LOGD_SETTINGS, "SettingsPlugin-Ofono: context '%s' (%s) already 
exported",
+                                    name, id);
+                       goto next_context;
+               }
+
+               /* add the new connection */
+               exported = nm_ofono_connection_new (context);
+               nm_log_info (LOGD_SETTINGS, "SettingsPlugin-Ofono: adding %s (%s) to connections", name, 
uuid);
+
+               /* FIXME: investigate if it's possible to set directly via g_object_* method...  */
+               /* Lower disabled timer to 30s */
+               nm_settings_connection_set_reset_retries_timeout (NM_SETTINGS_CONNECTION (exported), 30);
+
+               g_hash_table_insert (priv->connections, g_strdup (uuid), exported);
+               g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, exported);
+
+next_context:
+               g_free (uuid);
+       }
+
+       /*
+        * Remove any connections that have the same IMSI
+        * as our current list of contexts *and* are not
+        * present in our current list ( ie. the context
+        * has been deleted ).
+        *
+        * TODO: note, could this be handled directly by
+        * the imsi_monitor???  If so, it gets rid of
+        * this loop.  Doing so would require caching
+        * the preferred contexts for each IMSI
+        */
+       g_hash_table_iter_init (&iter, priv->connections);
+
+       while (g_hash_table_iter_next (&iter, &key, NULL)) {
+               char **context_id;
+               const char *idstr;
+
+               uuid = (char *) key;
+
+               found = g_hash_table_lookup_extended (uuids, uuid, NULL, NULL);
+               if (!found) {
+                       exported = g_hash_table_lookup (priv->connections, uuid);
+                       idstr = nm_connection_get_id (NM_CONNECTION (exported));
+                       context_id = g_strsplit (idstr, "/", 0);
+                       g_assert (context_id[2]);
+
+                       if (g_strcmp0(imsi, context_id[1]) == 0) {
+
+                               nm_log_info (LOGD_SETTINGS, "SettingsPlugin-Ofono: removing (%s) from 
connections", idstr);
+
+                               nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (exported));
+                               g_hash_table_remove (priv->connections, uuid);
+                       }
+
+                       g_strfreev (context_id);
+               }
+       }
+
+       if (uuids)
+               g_hash_table_destroy (uuids);
+}
+
+static gboolean
+nm_ofono_read_imsi_contexts (SettingsPluginOfono *self, const char *imsi, GError **error)
+{
+       GHashTable *context;
+       GHashTable *pref_context = NULL;
+       GSList *contexts = NULL;
+       GDir *imsi_dir;
+       const char *file;
+       gchar **groups;
+       gchar **keys, *imsi_path, *file_path;
+       gboolean res;
+       GKeyFile *keyfile = NULL;
+       GError *tmp_error = NULL;
+
+       imsi_path = g_strdup_printf (OFONO_CONFIG_DIR "/%s", imsi);
+       imsi_dir = g_dir_open (imsi_path, 0, NULL);
+
+       nm_log_info (LOGD_SETTINGS, "SettingsPlugin-Ofono: reading configuration for IMSI %s", imsi);
+       while (imsi_dir && (file = g_dir_read_name (imsi_dir)) != NULL) {
+               int i, j;
+
+               if (tmp_error)
+                       g_clear_error (&tmp_error);
+
+               /* Skip files not named "gprs" */
+               if (!!g_strcmp0 (file, "gprs"))
+                       continue;
+
+               keyfile = g_key_file_new ();
+               file_path = g_strdup_printf ("%s/%s", imsi_path, file);
+               res = g_key_file_load_from_file (keyfile, file_path, G_KEY_FILE_NONE, &tmp_error);
+               g_free (file_path);
+
+               if (!res) {
+                       nm_log_warn (LOGD_SETTINGS, "SettingsPlugin-Ofono: error reading %s: %s",
+                                    imsi,
+                                    tmp_error && tmp_error->message ? tmp_error->message : "(unknown)");
+                       continue;
+               }
+
+               groups = g_key_file_get_groups (keyfile, NULL);
+               for (i = 0; groups[i]; i++) {
+                       if (!g_strrstr (groups[i], "context"))
+                               continue;
+
+                       g_clear_error (&tmp_error);
+                       keys = g_key_file_get_keys (keyfile, groups[i], NULL, &tmp_error);
+                       if (tmp_error) {
+                               continue;
+                       }
+
+                       context = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+                       g_hash_table_insert (context, "ID", g_strdup (groups[i]));
+                       g_hash_table_insert (context, "IMSI", g_strdup (imsi));
+
+                       for (j = 0; keys[j]; j++) {
+                               gchar *prop_value;
+
+                               prop_value = g_key_file_get_string (keyfile, groups[i], keys[j], NULL);
+
+                               /*
+                                * FIXME: if file notify fires multiple times when 'pref' is updated,
+                                * need someway to cache the new 'Pref' value, so subequent file changes
+                                * are just ignored if 'Pref' hasn't changed...
+                                *
+                                * Note, when 'Preferred' gets set to 'true', this also causes the
+                                * 'Settings' and 'Active' properties to be updated, which triggers
+                                * the imsi_monitor and causes this function to be called also.
+                                */
+
+                               if (!strcmp (keys[j], "Type") && strcmp (prop_value, "internet")) {
+
+                                       g_hash_table_destroy (context);
+                                       g_free (prop_value);
+
+                                       goto next_context;
+                               }
+
+                               /* If more than one context is 'Preferred', first one wins... */
+                               if (!strcmp (keys[j], "Preferred") && !strcmp (prop_value, "true")) {
+                                       nm_log_info (LOGD_SETTINGS, "SettingsPlugin-Ofono: '%s' - Preferred = 
'true'", groups[i]);
+
+                                       pref_context = context;
+                               }
+
+                               if (!strcmp (keys[j], "Name"))
+                                       g_hash_table_insert (context, "Name", prop_value);
+                       }
+
+                       if (pref_context != NULL) {
+                               /*
+                                * Preferred context found, free any contexts created
+                                * before the preferred context was found.
+                                */
+
+                               if (contexts) {
+                                       g_slist_free_full (contexts, (GDestroyNotify) g_hash_table_destroy);
+                                       contexts = NULL;
+                               }
+
+                               contexts = g_slist_append (contexts, pref_context);
+                               break;
+                       } else
+                               contexts = g_slist_append (contexts, context);
+next_context:
+                       if (keys)
+                               g_strfreev (keys);
+               }
+
+               g_key_file_free (keyfile);
+               g_strfreev (groups);
+       }
+
+       g_free (imsi_path);
+
+       if (imsi_dir)
+               g_dir_close (imsi_dir);
+
+       SettingsPluginOfono_parse_contexts (self, contexts, imsi);
+
+       if (contexts) {
+               g_slist_free_full (contexts, (GDestroyNotify) g_hash_table_destroy);
+               contexts = NULL;
+               g_clear_error (&tmp_error);
+               return TRUE;
+       }
+
+       if (tmp_error) {
+               g_propagate_error (error, tmp_error);
+               g_clear_error (&tmp_error);
+       }
+       else {
+               g_set_error (error,
+                            ofono_plugin_error_quark (),
+                             0,
+                            "No contexts were found.");
+       }
+
+       return FALSE;
+}
+
+static gboolean
+SettingsPluginOfono_should_ignore_imsi (const char *imsi)
+{
+       /* Ignore paths that are not IMSI */
+       if (g_strcmp0 (imsi, "ofono") == 0)
+               return TRUE;
+
+       /* Ignore IMSI paths with dashes */
+       if (g_strrstr (imsi, "-") != NULL)
+               return TRUE;
+
+       return FALSE;
+}
+
+static void
+ofono_imsi_changed (GFileMonitor *monitor,
+                   GFile *file,
+                   GFile *other_file,
+                   GFileMonitorEvent event_type,
+                   gpointer user_data)
+{
+       SettingsPluginOfono *self = SETTINGS_PLUGIN_OFONO (user_data);
+       GFile *parent;
+       gchar *path, *imsi;
+       GError *error = NULL;
+
+       path = g_file_get_path (file);
+
+       /* If this isn't about a "gprs" file we don't want to know */
+       if (g_strrstr (path, "gprs") == NULL)
+               goto out_imsi;
+
+       switch (event_type) {
+               case G_FILE_MONITOR_EVENT_DELETED:
+                       nm_log_info (LOGD_SETTINGS, "SettingsPluginOfono: %s got removed.", path);
+                       break;
+               case G_FILE_MONITOR_EVENT_CREATED:
+               case G_FILE_MONITOR_EVENT_CHANGED:
+               case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+                       parent = g_file_get_parent (file);
+                       imsi = g_file_get_basename (parent);
+
+                       if (!nm_ofono_read_imsi_contexts (self, imsi, &error)) {
+                               nm_log_warn (LOGD_SETTINGS, "SettingsPluginOfono: an error occured while 
reading "
+                                            "contexts for IMSI %s", imsi);
+                       }
+
+                       g_object_unref (parent);
+                       g_free (imsi);
+                       break;
+               default:
+                       nm_log_warn (LOGD_SETTINGS, "SettingsPluginOfono: unexpected event type '%d'", (int) 
event_type);
+                       break;
+       }
+
+out_imsi:
+       g_free (path);
+
+       return;
+}
+
+static gboolean
+add_gprs_file_watch(SettingsPluginOfono *self, const char *imsi)
+{
+
+       SettingsPluginOfonoPrivate *priv = SETTINGS_PLUGIN_OFONO_GET_PRIVATE (self);
+       gchar *path;
+       GFile *config_path;
+       GFileMonitor *imsi_monitor;
+       gulong id;
+       const char *id_str;
+       gboolean result = FALSE;
+
+       id_str = g_hash_table_lookup (priv->ofono_imsi_monitor_ids, imsi);
+       if (id_str != NULL) {
+               nm_log_warn (LOGD_SETTINGS, "SettingsPluginOfono: file_monitor already exists for %s", imsi);
+               goto done;
+       }
+
+       path = g_strdup_printf (OFONO_CONFIG_DIR "/%s", imsi);
+
+       /*
+        * TODO: an optimiztion woudld be to add only monitor the directory
+        * if /<IMSI>/gprs doesn't yet exist.  Otherwise, a regular file
+        * monitor could be used, cutting down the times NM gets notified
+        * for changes to other ofono settings files...
+        */
+
+       config_path = g_file_new_for_path (path);
+       imsi_monitor = g_file_monitor_directory (config_path,
+                                                G_FILE_MONITOR_NONE,
+                                                NULL, NULL);
+
+       g_object_unref (config_path);
+       g_free (path);
+
+       if (imsi_monitor) {
+               nm_log_info (LOGD_SETTINGS, "SettingsPluginOfono: watching file changes for %s", imsi);
+               id = g_signal_connect (imsi_monitor, "changed",
+                                      G_CALLBACK (ofono_imsi_changed),
+                                      self);
+               g_hash_table_insert (priv->ofono_imsi_monitors,
+                                    g_strdup (imsi),
+                                    g_object_ref (imsi_monitor));
+               g_hash_table_insert (priv->ofono_imsi_monitor_ids,
+                                    g_strdup (imsi),
+                                    (gpointer) id);
+               g_object_unref (imsi_monitor);
+
+               result = TRUE;
+       } else {
+               nm_log_warn (LOGD_SETTINGS, "SettingsPluginOfono: couldn't create file monitor for %s.", 
imsi);
+       }
+
+done:
+       return result;
+}
+
+static void
+ofono_dir_changed (GFileMonitor *monitor,
+                   GFile *file,
+                   GFile *other_file,
+                   GFileMonitorEvent event_type,
+                   gpointer user_data)
+{
+       SettingsPluginOfono *self = SETTINGS_PLUGIN_OFONO (user_data);
+       SettingsPluginOfonoPrivate *priv = SETTINGS_PLUGIN_OFONO_GET_PRIVATE (self);
+       GFileMonitor *imsi_monitor;
+       gulong id;
+       gchar *imsi;
+       gboolean res;
+       GError *error = NULL;
+
+       imsi = g_file_get_basename (file);
+
+       if (SettingsPluginOfono_should_ignore_imsi (imsi))
+               goto out_ofono;
+
+       switch (event_type) {
+               case G_FILE_MONITOR_EVENT_DELETED:
+                       nm_log_info (LOGD_SETTINGS, "SettingsPluginOfono: removed %s.", imsi);
+
+                       /* Disable and remove the monitor, since the directory was deleted */
+                       imsi_monitor = g_hash_table_lookup (priv->ofono_imsi_monitors, imsi);
+                       id = (gulong) g_hash_table_lookup (priv->ofono_imsi_monitor_ids, imsi);
+
+                       if (imsi_monitor) {
+                               if (id)
+                                       g_signal_handler_disconnect (imsi_monitor, id);
+
+                               g_file_monitor_cancel (imsi_monitor);
+                               g_hash_table_remove (priv->ofono_imsi_monitors, imsi);
+                       }
+
+                       break;
+               case G_FILE_MONITOR_EVENT_CREATED:
+               case G_FILE_MONITOR_EVENT_CHANGED:
+               case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+
+                       /* TODO: is this a valid test?  If only new dirs and/or files created in
+                        * the config dir ( /var/lib/ofono ), and not it's sub-dirs, then if
+                        * there's no trailing slash, then it's a new IMSI directory.  Also
+                        * determine if writes to gprs files cause CHANGE events in the top-level
+                        * dir.... */
+
+                       /* Add watches for the IMSI directories too */
+                       if ((g_strrstr (imsi, "gprs") == NULL) && add_gprs_file_watch (self, imsi)) {
+
+                                       res = nm_ofono_read_imsi_contexts (self, imsi, &error);
+                                       if (!res)
+                                               nm_log_warn (LOGD_SETTINGS, "SettingsPluginOfono: an error 
occured while reading "
+                                                            "contexts for IMSI %s", imsi);
+                       }
+
+               default:
+                       break;
+       }
+
+out_ofono:
+       g_free (imsi);
+
+       return;
+}
+
+static void
+SettingsPluginOfono_read_context_files (SettingsPluginOfono *self)
+{
+       SettingsPluginOfonoPrivate *priv = SETTINGS_PLUGIN_OFONO_GET_PRIVATE (self);
+       GDir *config;
+       GFile *config_path;
+       GFileMonitor *monitor;
+       const char *imsi;
+       gboolean res = FALSE;
+       GError *error = NULL;
+
+       /* Hook up a GFileMonitor to watch for new context directories being created.
+        * This is in case ofono's provisioning plugin hasn't run when NM and the
+        * ofono settings plugin are started, and to pick up new created contexts.
+        */
+       config_path = g_file_new_for_path (OFONO_CONFIG_DIR);
+       if (g_file_query_exists (config_path, NULL)) {
+
+               monitor = g_file_monitor_directory (config_path, G_FILE_MONITOR_NONE,
+                                                   NULL, NULL);
+
+               if (monitor) {
+                       priv->ofono_dir_monitor = monitor;
+               } else {
+                       nm_log_warn (LOGD_SETTINGS, "SettingsPlugin-Ofono: couldn't create dir monitor");
+                       goto done;
+               }
+       } else {
+               nm_log_warn (LOGD_SETTINGS, "SettingsPlugin-Ofono: file doesn't exist: /var/lib/ofono");
+               goto done;
+               return;
+       }
+
+       config = g_dir_open (OFONO_CONFIG_DIR, 0, NULL);
+       while ((imsi = g_dir_read_name (config)) != NULL) {
+
+               if (SettingsPluginOfono_should_ignore_imsi (imsi))
+                       continue;
+
+               res = nm_ofono_read_imsi_contexts (self, imsi, &error);
+
+               if (error && error->message)
+                       nm_log_warn (LOGD_SETTINGS, "SettingsPlugin-Ofono: %s", error->message);
+
+               /* TODO: could go into read_imsi_contexts? */
+               add_gprs_file_watch(self, imsi);
+       }
+
+       priv->ofono_dir_monitor_id = g_signal_connect (monitor, "changed",
+                                                      G_CALLBACK (ofono_dir_changed), self);
+done:
+       g_object_unref (config_path);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void
+settings_plugin_ofono_class_init (SettingsPluginOfonoClass *req_class);
+
+static void
+SettingsPluginOfono_init (NMSettingsPlugin *config);
+
+static GSList *
+SettingsPluginOfono_get_unmanaged_specs (NMSettingsPlugin *config);
+
+/* Returns the plugins currently known list of connections.  The returned
+ * list is freed by the system settings service.
+ */
+static GSList*
+SettingsPluginOfono_get_connections (NMSettingsPlugin *config);
+
+static void
+GObject__get_property (GObject *object, guint prop_id,
+                                  GValue *value, GParamSpec *pspec)
+{
+       switch (prop_id) {
+       case NM_SETTINGS_PLUGIN_PROP_NAME:
+               g_value_set_string (value, OFONO_PLUGIN_NAME);
+               break;
+       case NM_SETTINGS_PLUGIN_PROP_INFO:
+               g_value_set_string (value, OFONO_PLUGIN_INFO);
+               break;
+       case NM_SETTINGS_PLUGIN_PROP_CAPABILITIES:
+               g_value_set_uint (value, 0);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+GObject__set_property (GObject *object, guint prop_id,
+                                  const GValue *value, GParamSpec *pspec)
+{
+       switch (prop_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+/*  GObject */
+static void
+dispose (GObject *object);
+
+static void
+settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface)
+{
+       plugin_iface->init = SettingsPluginOfono_init;
+       plugin_iface->get_connections = SettingsPluginOfono_get_connections;
+       plugin_iface->get_unmanaged_specs = SettingsPluginOfono_get_unmanaged_specs;
+}
+
+static void
+settings_plugin_ofono_class_init (SettingsPluginOfonoClass *req_class)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (req_class);
+
+       g_type_class_add_private (req_class, sizeof (SettingsPluginOfonoPrivate));
+
+       object_class->dispose = dispose;
+       object_class->get_property = GObject__get_property;
+       object_class->set_property = GObject__set_property;
+
+       g_object_class_override_property (object_class,
+                                         NM_SETTINGS_PLUGIN_PROP_NAME,
+                                         NM_SETTINGS_PLUGIN_NAME);
+
+       g_object_class_override_property (object_class,
+                                         NM_SETTINGS_PLUGIN_PROP_INFO,
+                                         NM_SETTINGS_PLUGIN_INFO);
+
+       g_object_class_override_property (object_class,
+                                         NM_SETTINGS_PLUGIN_PROP_CAPABILITIES,
+                                         NM_SETTINGS_PLUGIN_CAPABILITIES);
+}
+
+static void
+SettingsPluginOfono_init (NMSettingsPlugin *config)
+{
+       SettingsPluginOfono *self = SETTINGS_PLUGIN_OFONO (config);
+       SettingsPluginOfonoPrivate *priv = SETTINGS_PLUGIN_OFONO_GET_PRIVATE (self);
+
+       /* Keep a hash table of GFileMonitors per IMSI for later removal */
+       if (!priv->ofono_imsi_monitors)
+               priv->ofono_imsi_monitors = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, 
g_object_unref);
+
+       if (!priv->ofono_imsi_monitor_ids)
+               priv->ofono_imsi_monitor_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+       if(!priv->connections)
+               priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+
+       nm_log_info (LOGD_SETTINGS, "SettingsPlugin-Ofono: init!");
+
+       SettingsPluginOfono_read_context_files (self);
+
+       nm_log_info (LOGD_SETTINGS, "SettingsPlugin-Ofono: end _init.");
+}
+
+static GSList *
+SettingsPluginOfono_get_unmanaged_specs (NMSettingsPlugin *config)
+{
+       return NULL;
+}
+
+static gint
+sort_by_context_id (gconstpointer a, gconstpointer b)
+{
+       const char *context_a;
+       const char *context_b;
+
+       g_return_val_if_fail (a != NULL, 0);
+       g_return_val_if_fail (b != NULL, 0);
+
+       context_a = nm_connection_get_id (NM_CONNECTION (a));
+       context_b = nm_connection_get_id (NM_CONNECTION (b));
+
+       return g_strcmp0 (context_a, context_b);
+}
+
+/* Returns the plugins currently known list of connections.  The returned
+ * list is freed by the system settings service.
+ */
+static GSList*
+SettingsPluginOfono_get_connections (NMSettingsPlugin *config)
+{
+       SettingsPluginOfonoPrivate *priv = SETTINGS_PLUGIN_OFONO_GET_PRIVATE (config);
+       GSList *connections = NULL;
+       GHashTableIter iter;
+       gpointer value;
+
+       nm_log_info (LOGD_SETTINGS, "SettingsPlugin-Ofono: (%d) ... get_connections.", 
GPOINTER_TO_UINT(config));
+
+       g_hash_table_iter_init (&iter, priv->connections);
+       while (g_hash_table_iter_next (&iter, NULL, &value))
+               connections = g_slist_prepend (connections, value);
+
+       connections = g_slist_sort (connections, sort_by_context_id);
+
+       nm_log_info (LOGD_SETTINGS, "SettingsPlugin-Ofono: (%d) connections count: %d", 
GPOINTER_TO_UINT(config), g_slist_length(connections));
+       return connections;
+}
+
+static void
+settings_plugin_ofono_init (SettingsPluginOfono *plugin)
+{
+}
+
+static void
+cancel_monitor (gpointer key, gpointer value, gpointer user_data)
+{
+       GHashTable *monitor_ids = user_data;
+       GFileMonitor *monitor = (GFileMonitor *) value;
+       gchar *imsi = (gchar *) key;
+       gulong id;
+
+       if (monitor_ids) {
+               id = (gulong) g_hash_table_lookup (monitor_ids, imsi);
+               g_signal_handler_disconnect (monitor, id);
+       }
+
+       g_file_monitor_cancel (monitor);
+
+       return;
+}
+
+static void
+dispose (GObject *object)
+{
+       SettingsPluginOfono *plugin = SETTINGS_PLUGIN_OFONO (object);
+       SettingsPluginOfonoPrivate *priv = SETTINGS_PLUGIN_OFONO_GET_PRIVATE (plugin);
+
+       if (priv->ofono_dir_monitor) {
+               if (priv->ofono_dir_monitor_id)
+                       g_signal_handler_disconnect (priv->ofono_dir_monitor,
+                                                    priv->ofono_dir_monitor_id);
+
+               g_file_monitor_cancel (priv->ofono_dir_monitor);
+               g_object_unref (priv->ofono_dir_monitor);
+               priv->ofono_dir_monitor = NULL;
+       }
+
+       if (priv->ofono_imsi_monitors) {
+               g_hash_table_foreach (priv->ofono_imsi_monitors, cancel_monitor, 
priv->ofono_imsi_monitor_ids);
+
+               g_hash_table_destroy (priv->ofono_imsi_monitors);
+               priv->ofono_imsi_monitors = NULL;
+
+               if (priv->ofono_imsi_monitor_ids) {
+                       g_hash_table_destroy (priv->ofono_imsi_monitor_ids);
+                       priv->ofono_imsi_monitor_ids = NULL;
+               }
+       }
+
+       if (priv->connections) {
+               g_hash_table_destroy (priv->connections);
+               priv->connections = NULL;
+       }
+
+       G_OBJECT_CLASS (settings_plugin_ofono_parent_class)->dispose (object);
+}
+
+G_MODULE_EXPORT GObject *
+nm_settings_plugin_factory (void)
+{
+       static SettingsPluginOfono *singleton = NULL;
+       SettingsPluginOfonoPrivate *priv;
+
+       if (!singleton) {
+               singleton = SETTINGS_PLUGIN_OFONO (g_object_new (SETTINGS_TYPE_PLUGIN_OFONO, NULL));
+               if (singleton) {
+                       priv = SETTINGS_PLUGIN_OFONO_GET_PRIVATE (singleton);
+               }
+       } else
+               g_object_ref (singleton);
+
+       return G_OBJECT (singleton);
+}
+
diff --git a/src/settings/plugins/ofono/plugin.h b/src/settings/plugins/ofono/plugin.h
new file mode 100644
index 0000000..d8b81f9
--- /dev/null
+++ b/src/settings/plugins/ofono/plugin.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
+/* NetworkManager system settings service (ofono)
+ *
+ * Mathieu Trudel-Lapierre <mathieu-tl ubuntu com>
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2013-2016 Canonical Ltd.
+ */
+
+#ifndef _PLUGIN_H_
+#define _PLUGIN_H_
+
+#include <glib-object.h>
+
+#define PLUGIN_NAME "ofono"
+
+#define SETTINGS_TYPE_PLUGIN_OFONO            (settings_plugin_ofono_get_type ())
+#define SETTINGS_PLUGIN_OFONO(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
SETTINGS_TYPE_PLUGIN_OFONO, SettingsPluginOfono))
+#define SETTINGS_PLUGIN_OFONO_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SETTINGS_TYPE_PLUGIN_OFONO, 
SettingsPluginOfonoClass))
+#define SETTINGS_IS_PLUGIN_OFONO(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
SETTINGS_TYPE_PLUGIN_OFONO))
+#define SETTINGS_IS_PLUGIN_OFONO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SETTINGS_TYPE_PLUGIN_OFONO))
+#define SETTINGS_PLUGIN_OFONO_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SETTINGS_TYPE_PLUGIN_OFONO, 
SettingsPluginOfonoClass))
+
+typedef struct _SettingsPluginOfono SettingsPluginOfono;
+typedef struct _SettingsPluginOfonoClass SettingsPluginOfonoClass;
+
+struct _SettingsPluginOfono {
+       GObject parent;
+};
+
+struct _SettingsPluginOfonoClass {
+       GObjectClass parent;
+};
+
+GType settings_plugin_ofono_get_type (void);
+
+GQuark ofono_plugin_error_quark (void);
+
+#endif /* _PLUGIN_H_ */
-- 
2.7.4




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]