aboutsummaryrefslogtreecommitdiff
path: root/libmm-glib
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-10-02 15:08:46 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-10-04 10:17:05 +0200
commitb6d628b3a10bf183b918c7afe89a5b260eb87760 (patch)
tree8d87e92f2d8b7da99e6a0e41e49a6aa0ebbf55bd /libmm-glib
parent624fdb6ab4544a82774e9805332cc242c1068b0f (diff)
build: merge libmm-common into libmm-glib
It's pointless to have libmm-common around, just merge it into libmm-glib and make ModemManager depend on libmm-glib directly. At the end, the non-common stuff in libmm-glib is really minimal.
Diffstat (limited to 'libmm-glib')
-rw-r--r--libmm-glib/Makefile.am63
-rw-r--r--libmm-glib/generated/Makefile.am189
-rw-r--r--libmm-glib/libmm-common.h46
-rw-r--r--libmm-glib/mm-bearer-ip-config.c332
-rw-r--r--libmm-glib/mm-bearer-ip-config.h73
-rw-r--r--libmm-glib/mm-bearer-properties.c513
-rw-r--r--libmm-glib/mm-bearer-properties.h94
-rw-r--r--libmm-glib/mm-common-helpers.c901
-rw-r--r--libmm-glib/mm-common-helpers.h99
-rw-r--r--libmm-glib/mm-firmware-properties.c300
-rw-r--r--libmm-glib/mm-firmware-properties.h68
-rw-r--r--libmm-glib/mm-location-3gpp.c280
-rw-r--r--libmm-glib/mm-location-3gpp.h68
-rw-r--r--libmm-glib/mm-location-gps-nmea.c248
-rw-r--r--libmm-glib/mm-location-gps-nmea.h61
-rw-r--r--libmm-glib/mm-location-gps-raw.c337
-rw-r--r--libmm-glib/mm-location-gps-raw.h70
-rw-r--r--libmm-glib/mm-network-timezone.c216
-rw-r--r--libmm-glib/mm-network-timezone.h68
-rw-r--r--libmm-glib/mm-simple-connect-properties.c582
-rw-r--r--libmm-glib/mm-simple-connect-properties.h98
-rw-r--r--libmm-glib/mm-simple-status.c599
-rw-r--r--libmm-glib/mm-simple-status.h85
-rw-r--r--libmm-glib/mm-sms-properties.c586
-rw-r--r--libmm-glib/mm-sms-properties.h87
-rw-r--r--libmm-glib/mm-unlock-retries.c218
-rw-r--r--libmm-glib/mm-unlock-retries.h78
-rw-r--r--libmm-glib/tests/Makefile.am27
-rw-r--r--libmm-glib/tests/test-common-helpers.c529
29 files changed, 6904 insertions, 11 deletions
diff --git a/libmm-glib/Makefile.am b/libmm-glib/Makefile.am
index 9f93b699..4c46e466 100644
--- a/libmm-glib/Makefile.am
+++ b/libmm-glib/Makefile.am
@@ -1,14 +1,7 @@
+SUBDIRS = generated . tests
lib_LTLIBRARIES = libmm-glib.la
-libmm_glib_la_CPPFLAGS = \
- $(LIBMM_GLIB_CFLAGS) \
- -I$(top_srcdir) \
- -I$(top_srcdir)/include \
- -I$(top_builddir)/include \
- -I${top_srcdir}/libmm-common \
- -I${top_builddir}/libmm-common
-
libmm_glib_la_SOURCES = \
libmm-glib.h \
mm-helpers.h \
@@ -39,10 +32,46 @@ libmm_glib_la_SOURCES = \
mm-modem-messaging.h \
mm-modem-messaging.c \
mm-bearer.h \
- mm-bearer.c
+ mm-bearer.c \
+ mm-common-helpers.h \
+ mm-common-helpers.c \
+ mm-simple-status.h \
+ mm-simple-status.c \
+ mm-simple-connect-properties.h \
+ mm-simple-connect-properties.c \
+ mm-bearer-properties.h \
+ mm-bearer-properties.c \
+ mm-sms-properties.h \
+ mm-sms-properties.c \
+ mm-bearer-ip-config.h \
+ mm-bearer-ip-config.c \
+ mm-location-3gpp.h \
+ mm-location-3gpp.c \
+ mm-location-gps-raw.h \
+ mm-location-gps-raw.c \
+ mm-location-gps-nmea.h \
+ mm-location-gps-nmea.c \
+ mm-unlock-retries.h \
+ mm-unlock-retries.c \
+ mm-network-timezone.h \
+ mm-network-timezone.c \
+ mm-firmware-properties.h \
+ mm-firmware-properties.c
+
+nodist_libmm_glib_la_SOURCES = \
+ $(GENERATED_H) \
+ $(GENERATED_C)
+
+libmm_glib_la_CPPFLAGS = \
+ $(LIBMM_GLIB_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/include \
+ -I$(top_builddir)/include \
+ -I${top_srcdir}/libmm-glib/generated \
+ -I${top_builddir}/libmm-glib/generated
libmm_glib_la_LIBADD = \
- $(top_builddir)/libmm-common/libmm-common.la \
+ ${top_builddir}/libmm-glib/generated/libmm-generated.la \
$(LIBMM_GLIB_LIBS)
includedir = @includedir@/libmm-glib
@@ -61,4 +90,16 @@ include_HEADERS = \
mm-modem-simple.h \
mm-sim.h \
mm-sms.h \
- mm-bearer.h
+ mm-bearer.h \
+ mm-common-helpers.h \
+ mm-simple-status.h \
+ mm-simple-connect-properties.h \
+ mm-bearer-properties.h \
+ mm-sms-properties.h \
+ mm-bearer-ip-config.h \
+ mm-location-3gpp.h \
+ mm-location-gps-nmea.h \
+ mm-location-gps-raw.h \
+ mm-unlock-retries.h \
+ mm-network-timezone.h \
+ mm-firmware-properties.h
diff --git a/libmm-glib/generated/Makefile.am b/libmm-glib/generated/Makefile.am
new file mode 100644
index 00000000..0eea84c7
--- /dev/null
+++ b/libmm-glib/generated/Makefile.am
@@ -0,0 +1,189 @@
+
+noinst_LTLIBRARIES = libmm-generated.la
+
+GENERATED_H = \
+ mm-enums-types.h \
+ mm-errors-types.h \
+ mm-gdbus-manager.h \
+ mm-gdbus-sim.h \
+ mm-gdbus-sms.h \
+ mm-gdbus-bearer.h \
+ mm-gdbus-modem.h
+
+GENERATED_C = \
+ mm-enums-types.c \
+ mm-errors-types.c \
+ mm-errors-quarks.c \
+ mm-gdbus-manager.c \
+ mm-gdbus-sim.c \
+ mm-gdbus-sms.c \
+ mm-gdbus-bearer.c \
+ mm-gdbus-modem.c
+
+GENERATED_DOC = \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Sim.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Sms.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Bearer.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Messaging.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Location.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Time.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Firmware.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Contacts.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.ModemCdma.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Modem3gpp.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Modem3gpp.Ussd.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Simple.xml
+
+BUILT_SOURCES = $(GENERATED_H) $(GENERATED_C) $(GENERATED_DOC)
+
+# Enum types
+mm-enums-types.h: Makefile.am $(top_srcdir)/include/ModemManager-enums.h $(top_srcdir)/build-aux/mm-enums-template.h
+ $(AM_V_GEN) $(GLIB_MKENUMS) \
+ --fhead "#include <ModemManager-enums.h>\n#ifndef __MM_ENUMS_TYPES_H__\n#define __MM_ENUMS_TYPES_H__\n" \
+ --template $(top_srcdir)/build-aux/mm-enums-template.h \
+ --ftail "#endif /* __MM_ENUMS_TYPES_H__ */\n" \
+ $(top_srcdir)/include/ModemManager-enums.h > $@
+
+mm-enums-types.c: Makefile.am $(top_srcdir)/include/ModemManager-enums.h $(top_srcdir)/build-aux/mm-enums-template.c mm-enums-types.h
+ $(AM_V_GEN) $(GLIB_MKENUMS) \
+ --fhead "#include \"mm-enums-types.h\"\n" \
+ --template $(top_srcdir)/build-aux/mm-enums-template.c \
+ $(top_srcdir)/include/ModemManager-enums.h > $@
+
+# Error types & quarks
+mm-errors-types.h: Makefile.am $(top_srcdir)/include/ModemManager-errors.h $(top_srcdir)/build-aux/mm-errors-template.h
+ $(AM_V_GEN) $(GLIB_MKENUMS) \
+ --fhead "#ifndef __MM_ERRORS_TYPES_H__\n#define __MM_ERRORS_TYPES_H__\n" \
+ --template $(top_srcdir)/build-aux/mm-errors-template.h \
+ --ftail "#endif /* __MM_ERRORS_TYPES_H__ */\n" \
+ $(top_srcdir)/include/ModemManager-errors.h > $@
+
+mm-errors-types.c: Makefile.am $(top_srcdir)/include/ModemManager-errors.h $(top_srcdir)/build-aux/mm-errors-template.c mm-errors-types.h
+ $(AM_V_GEN) $(GLIB_MKENUMS) \
+ --fhead "#include <ModemManager-errors.h>\n#include \"mm-errors-types.h\"\n" \
+ --template $(top_srcdir)/build-aux/mm-errors-template.c \
+ $(top_srcdir)/include/ModemManager-errors.h > $@
+
+mm-errors-quarks.c: Makefile.am $(top_srcdir)/include/ModemManager-errors.h $(top_srcdir)/build-aux/mm-errors-quarks-template.c $(top_srcdir)/include/ModemManager-names.h mm-errors-types.h
+ $(AM_V_GEN) $(GLIB_MKENUMS) \
+ --fhead "#include <ModemManager-errors.h>\n#include \"mm-errors-types.h\"\n" \
+ --template $(top_srcdir)/build-aux/mm-errors-quarks-template.c \
+ $(top_srcdir)/include/ModemManager-errors.h > $@
+
+# Manager interface
+mm_gdbus_manager_generated = \
+ mm-gdbus-manager.h \
+ mm-gdbus-manager.c \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.xml
+$(mm_gdbus_manager_generated): $(top_srcdir)/introspection/org.freedesktop.ModemManager1.xml
+ $(AM_V_GEN) gdbus-codegen \
+ --interface-prefix org.freedesktop.ModemManager1. \
+ --c-namespace=MmGdbus \
+ --generate-docbook mm-gdbus-doc \
+ --generate-c-code mm-gdbus-manager \
+ $< \
+ $(NULL)
+
+# Modem interfaces
+mm_gdbus_modem_generated = \
+ mm-gdbus-modem.h \
+ mm-gdbus-modem.c \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Messaging.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Location.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Time.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Firmware.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Contacts.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.ModemCdma.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Modem3gpp.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Modem3gpp.Ussd.xml \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Modem.Simple.xml
+mm_gdbus_modem_deps = \
+ $(top_srcdir)/introspection/org.freedesktop.ModemManager1.Modem.xml \
+ $(top_srcdir)/introspection/org.freedesktop.ModemManager1.Modem.Messaging.xml \
+ $(top_srcdir)/introspection/org.freedesktop.ModemManager1.Modem.Location.xml \
+ $(top_srcdir)/introspection/org.freedesktop.ModemManager1.Modem.Time.xml \
+ $(top_srcdir)/introspection/org.freedesktop.ModemManager1.Modem.Firmware.xml \
+ $(top_srcdir)/introspection/org.freedesktop.ModemManager1.Modem.Contacts.xml \
+ $(top_srcdir)/introspection/org.freedesktop.ModemManager1.Modem.ModemCdma.xml \
+ $(top_srcdir)/introspection/org.freedesktop.ModemManager1.Modem.Modem3gpp.xml \
+ $(top_srcdir)/introspection/org.freedesktop.ModemManager1.Modem.Modem3gpp.Ussd.xml \
+ $(top_srcdir)/introspection/org.freedesktop.ModemManager1.Modem.Simple.xml
+$(mm_gdbus_modem_generated): $(mm_gdbus_modem_deps)
+ $(AM_V_GEN) gdbus-codegen \
+ --interface-prefix org.freedesktop.ModemManager1. \
+ --c-namespace=MmGdbus \
+ --generate-docbook mm-gdbus-doc \
+ --generate-c-code mm-gdbus-modem \
+ --c-generate-object-manager \
+ --annotate "org.freedesktop.ModemManager1.Modem.ModemCdma" org.gtk.GDBus.C.Name ModemCdma \
+ --annotate "org.freedesktop.ModemManager1.Modem.Modem3gpp" org.gtk.GDBus.C.Name Modem3gpp \
+ --annotate "org.freedesktop.ModemManager1.Modem.Modem3gpp.Ussd" org.gtk.GDBus.C.Name Modem3gppUssd \
+ $^ \
+ $(NULL)
+
+# SIM interface
+mm_gdbus_sim_generated = \
+ mm-gdbus-sim.h \
+ mm-gdbus-sim.c \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Sim.xml
+$(mm_gdbus_sim_generated): $(top_srcdir)/introspection/org.freedesktop.ModemManager1.Sim.xml
+ $(AM_V_GEN) gdbus-codegen \
+ --interface-prefix org.freedesktop.ModemManager1. \
+ --c-namespace=MmGdbus \
+ --generate-docbook mm-gdbus-doc \
+ --generate-c-code mm-gdbus-sim \
+ $< \
+ $(NULL)
+
+# Bearer interface
+mm_gdbus_bearer_generated = \
+ mm-gdbus-bearer.h \
+ mm-gdbus-bearer.c \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Bearer.xml
+$(mm_gdbus_bearer_generated): $(top_srcdir)/introspection/org.freedesktop.ModemManager1.Bearer.xml
+ $(AM_V_GEN) gdbus-codegen \
+ --interface-prefix org.freedesktop.ModemManager1. \
+ --c-namespace=MmGdbus \
+ --generate-docbook mm-gdbus-doc \
+ --generate-c-code mm-gdbus-bearer \
+ $< \
+ $(NULL)
+
+# SMS interface
+mm_gdbus_sms_generated = \
+ mm-gdbus-sms.h \
+ mm-gdbus-sms.c \
+ mm-gdbus-doc-org.freedesktop.ModemManager1.Sms.xml
+$(mm_gdbus_sms_generated): $(top_srcdir)/introspection/org.freedesktop.ModemManager1.Sms.xml
+ $(AM_V_GEN) gdbus-codegen \
+ --interface-prefix org.freedesktop.ModemManager1. \
+ --c-namespace=MmGdbus \
+ --generate-docbook mm-gdbus-doc \
+ --generate-c-code mm-gdbus-sms \
+ --annotate "org.freedesktop.ModemManager1.Sms:Data" org.gtk.GDBus.C.ForceGVariant True \
+ $< \
+ $(NULL)
+
+nodist_libmm_generated_la_SOURCES = \
+ $(GENERATED_H) \
+ $(GENERATED_C)
+
+libmm_generated_la_CPPFLAGS = \
+ $(LIBMM_GLIB_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/include \
+ -I$(top_builddir)/include \
+ -Wno-unused-function \
+ -Wno-float-equal \
+ -Wno-shadow
+
+libmm_generated_la_LIBADD = \
+ $(LIBMM_GLIB_LIBS)
+
+includedir = @includedir@/libmm-glib
+include_HEADERS = $(GENERATED_H)
+
+CLEANFILES = $(GENERATED_H) $(GENERATED_C) $(GENERATED_DOC)
diff --git a/libmm-glib/libmm-common.h b/libmm-glib/libmm-common.h
new file mode 100644
index 00000000..0404c892
--- /dev/null
+++ b/libmm-glib/libmm-common.h
@@ -0,0 +1,46 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * libmm-common -- Common library used by libmm-glib and ModemManager
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2011 Google, Inc.
+ */
+
+#ifndef _LIBMM_COMMON_H_
+#define _LIBMM_COMMON_H_
+
+#include "mm-errors-types.h"
+#include "mm-enums-types.h"
+#include "mm-common-helpers.h"
+#include "mm-simple-status.h"
+#include "mm-simple-connect-properties.h"
+#include "mm-sms-properties.h"
+#include "mm-bearer-properties.h"
+#include "mm-bearer-ip-config.h"
+#include "mm-location-3gpp.h"
+#include "mm-location-gps-raw.h"
+#include "mm-location-gps-nmea.h"
+#include "mm-unlock-retries.h"
+#include "mm-network-timezone.h"
+#include "mm-firmware-properties.h"
+#include "mm-gdbus-manager.h"
+#include "mm-gdbus-modem.h"
+#include "mm-gdbus-bearer.h"
+#include "mm-gdbus-sim.h"
+#include "mm-gdbus-sms.h"
+
+#endif /* _LIBMM_COMMON_H_ */
diff --git a/libmm-glib/mm-bearer-ip-config.c b/libmm-glib/mm-bearer-ip-config.c
new file mode 100644
index 00000000..06e7830e
--- /dev/null
+++ b/libmm-glib/mm-bearer-ip-config.c
@@ -0,0 +1,332 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Google, Inc.
+ */
+
+#include <string.h>
+
+#include "mm-errors-types.h"
+#include "mm-bearer-ip-config.h"
+
+G_DEFINE_TYPE (MMBearerIpConfig, mm_bearer_ip_config, G_TYPE_OBJECT);
+
+#define PROPERTY_METHOD "method"
+#define PROPERTY_ADDRESS "address"
+#define PROPERTY_PREFIX "prefix"
+#define PROPERTY_DNS1 "dns1"
+#define PROPERTY_DNS2 "dns2"
+#define PROPERTY_DNS3 "dns3"
+#define PROPERTY_GATEWAY "gateway"
+
+struct _MMBearerIpConfigPrivate {
+ MMBearerIpMethod method;
+ gchar *address;
+ guint prefix;
+ gchar **dns;
+ gchar *gateway;
+};
+
+/*****************************************************************************/
+
+void
+mm_bearer_ip_config_set_method (MMBearerIpConfig *self,
+ MMBearerIpMethod method)
+{
+ g_return_if_fail (MM_IS_BEARER_IP_CONFIG (self));
+
+ self->priv->method = method;
+}
+
+void
+mm_bearer_ip_config_set_address (MMBearerIpConfig *self,
+ const gchar *address)
+{
+ g_return_if_fail (MM_IS_BEARER_IP_CONFIG (self));
+
+ g_free (self->priv->address);
+ self->priv->address = g_strdup (address);
+}
+
+void
+mm_bearer_ip_config_set_prefix (MMBearerIpConfig *self,
+ guint prefix)
+{
+ g_return_if_fail (MM_IS_BEARER_IP_CONFIG (self));
+
+ self->priv->prefix = prefix;
+}
+
+void
+mm_bearer_ip_config_set_dns (MMBearerIpConfig *self,
+ const gchar **dns)
+{
+ g_return_if_fail (MM_IS_BEARER_IP_CONFIG (self));
+
+ g_strfreev (self->priv->dns);
+ self->priv->dns = g_strdupv ((gchar **)dns);
+}
+
+void
+mm_bearer_ip_config_set_gateway (MMBearerIpConfig *self,
+ const gchar *gateway)
+{
+ g_return_if_fail (MM_IS_BEARER_IP_CONFIG (self));
+
+ g_free (self->priv->gateway);
+ self->priv->gateway = g_strdup (gateway);
+}
+
+/*****************************************************************************/
+
+MMBearerIpMethod
+mm_bearer_ip_config_get_method (MMBearerIpConfig *self)
+{
+ g_return_val_if_fail (MM_IS_BEARER_IP_CONFIG (self), MM_BEARER_IP_METHOD_UNKNOWN);
+
+ return self->priv->method;
+}
+
+const gchar *
+mm_bearer_ip_config_get_address (MMBearerIpConfig *self)
+{
+ g_return_val_if_fail (MM_IS_BEARER_IP_CONFIG (self), NULL);
+
+ return self->priv->address;
+}
+
+guint
+mm_bearer_ip_config_get_prefix (MMBearerIpConfig *self)
+{
+ g_return_val_if_fail (MM_IS_BEARER_IP_CONFIG (self), 0);
+
+ return self->priv->prefix;
+}
+
+const gchar **
+mm_bearer_ip_config_get_dns (MMBearerIpConfig *self)
+{
+ g_return_val_if_fail (MM_IS_BEARER_IP_CONFIG (self), NULL);
+
+ return (const gchar **)self->priv->dns;
+}
+
+const gchar *
+mm_bearer_ip_config_get_gateway (MMBearerIpConfig *self)
+{
+ g_return_val_if_fail (MM_IS_BEARER_IP_CONFIG (self), NULL);
+
+ return self->priv->gateway;
+}
+
+/*****************************************************************************/
+
+GVariant *
+mm_bearer_ip_config_get_dictionary (MMBearerIpConfig *self)
+{
+ GVariantBuilder builder;
+
+ /* We do allow self==NULL. We'll just report method=unknown in this case */
+ if (self)
+ g_return_val_if_fail (MM_IS_BEARER_IP_CONFIG (self), NULL);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_METHOD,
+ g_variant_new_uint32 (self ?
+ self->priv->method :
+ MM_BEARER_IP_METHOD_UNKNOWN));
+
+ /* If static IP method, report remaining configuration */
+ if (self &&
+ self->priv->method == MM_BEARER_IP_METHOD_STATIC) {
+ if (self->priv->address)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_ADDRESS,
+ g_variant_new_string (self->priv->address));
+
+ if (self->priv->prefix)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_PREFIX,
+ g_variant_new_uint32 (self->priv->prefix));
+
+ if (self->priv->dns &&
+ self->priv->dns[0]) {
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_DNS1,
+ g_variant_new_string (self->priv->dns[0]));
+ if (self->priv->dns[1]) {
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_DNS2,
+ g_variant_new_string (self->priv->dns[1]));
+ if (self->priv->dns[2]) {
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_DNS3,
+ g_variant_new_string (self->priv->dns[2]));
+ }
+ }
+ }
+
+ if (self->priv->gateway)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_GATEWAY,
+ g_variant_new_string (self->priv->gateway));
+ }
+
+ return g_variant_builder_end (&builder);
+}
+
+/*****************************************************************************/
+
+MMBearerIpConfig *
+mm_bearer_ip_config_new_from_dictionary (GVariant *dictionary,
+ GError **error)
+{
+ GVariantIter iter;
+ gchar *key;
+ GVariant *value;
+ MMBearerIpConfig *self;
+ gchar *dns_array[4] = { 0 };
+ gboolean method_received = FALSE;
+
+ self = mm_bearer_ip_config_new ();
+ if (!dictionary)
+ return self;
+
+ if (!g_variant_is_of_type (dictionary, G_VARIANT_TYPE ("a{sv}"))) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create IP config from dictionary: "
+ "invalid variant type received");
+ g_object_unref (self);
+ return NULL;
+ }
+
+ g_variant_iter_init (&iter, dictionary);
+ while (g_variant_iter_next (&iter, "{sv}", &key, &value)) {
+ if (g_str_equal (key, PROPERTY_METHOD)) {
+ method_received = TRUE;
+ mm_bearer_ip_config_set_method (
+ self,
+ (MMBearerIpMethod) g_variant_get_uint32 (value));
+ } else if (g_str_equal (key, PROPERTY_ADDRESS))
+ mm_bearer_ip_config_set_address (
+ self,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_PREFIX))
+ mm_bearer_ip_config_set_prefix (
+ self,
+ g_variant_get_uint32 (value));
+ else if (g_str_equal (key, PROPERTY_DNS1)) {
+ g_free (dns_array[0]);
+ dns_array[0] = g_variant_dup_string (value, NULL);
+ } else if (g_str_equal (key, PROPERTY_DNS2)) {
+ g_free (dns_array[1]);
+ dns_array[1] = g_variant_dup_string (value, NULL);
+ } else if (g_str_equal (key, PROPERTY_DNS3)) {
+ g_free (dns_array[2]);
+ dns_array[2] = g_variant_dup_string (value, NULL);
+ } else if (g_str_equal (key, PROPERTY_GATEWAY))
+ mm_bearer_ip_config_set_gateway (
+ self,
+ g_variant_get_string (value, NULL));
+
+ g_free (key);
+ g_variant_unref (value);
+ }
+
+ if (dns_array[0])
+ mm_bearer_ip_config_set_dns (self, (const gchar **)dns_array);
+
+ if (!method_received) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Couldn't create IP config from dictionary: 'method not given'");
+ g_clear_object (&self);
+ }
+
+ g_free (dns_array[0]);
+ g_free (dns_array[1]);
+ g_free (dns_array[2]);
+
+ return self;
+}
+
+/*****************************************************************************/
+
+MMBearerIpConfig *
+mm_bearer_ip_config_dup (MMBearerIpConfig *orig)
+{
+ GVariant *dict;
+ MMBearerIpConfig *copy;
+ GError *error = NULL;
+
+ g_return_val_if_fail (MM_IS_BEARER_IP_CONFIG (orig), NULL);
+
+ dict = mm_bearer_ip_config_get_dictionary (orig);
+ copy = mm_bearer_ip_config_new_from_dictionary (dict, &error);
+ g_assert_no_error (error);
+ g_variant_unref (dict);
+
+ return copy;
+}
+
+/*****************************************************************************/
+
+MMBearerIpConfig *
+mm_bearer_ip_config_new (void)
+{
+ return (MM_BEARER_IP_CONFIG (
+ g_object_new (MM_TYPE_BEARER_IP_CONFIG, NULL)));
+}
+
+static void
+mm_bearer_ip_config_init (MMBearerIpConfig *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
+ MM_TYPE_BEARER_IP_CONFIG,
+ MMBearerIpConfigPrivate);
+
+ /* Some defaults */
+ self->priv->method = MM_BEARER_IP_METHOD_UNKNOWN;
+}
+
+static void
+finalize (GObject *object)
+{
+ MMBearerIpConfig *self = MM_BEARER_IP_CONFIG (object);
+
+ g_free (self->priv->address);
+ g_free (self->priv->gateway);
+ g_strfreev (self->priv->dns);
+
+ G_OBJECT_CLASS (mm_bearer_ip_config_parent_class)->finalize (object);
+}
+
+static void
+mm_bearer_ip_config_class_init (MMBearerIpConfigClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMBearerIpConfigPrivate));
+
+ object_class->finalize = finalize;
+}
diff --git a/libmm-glib/mm-bearer-ip-config.h b/libmm-glib/mm-bearer-ip-config.h
new file mode 100644
index 00000000..7fc6dd69
--- /dev/null
+++ b/libmm-glib/mm-bearer-ip-config.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Google, Inc.
+ */
+
+#ifndef MM_BEARER_IP_CONFIG_H
+#define MM_BEARER_IP_CONFIG_H
+
+#include <ModemManager.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MM_TYPE_BEARER_IP_CONFIG (mm_bearer_ip_config_get_type ())
+#define MM_BEARER_IP_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BEARER_IP_CONFIG, MMBearerIpConfig))
+#define MM_BEARER_IP_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BEARER_IP_CONFIG, MMBearerIpConfigClass))
+#define MM_IS_BEARER_IP_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BEARER_IP_CONFIG))
+#define MM_IS_BEARER_IP_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BEARER_IP_CONFIG))
+#define MM_BEARER_IP_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BEARER_IP_CONFIG, MMBearerIpConfigClass))
+
+typedef struct _MMBearerIpConfig MMBearerIpConfig;
+typedef struct _MMBearerIpConfigClass MMBearerIpConfigClass;
+typedef struct _MMBearerIpConfigPrivate MMBearerIpConfigPrivate;
+
+struct _MMBearerIpConfig {
+ GObject parent;
+ MMBearerIpConfigPrivate *priv;
+};
+
+struct _MMBearerIpConfigClass {
+ GObjectClass parent;
+};
+
+GType mm_bearer_ip_config_get_type (void);
+
+MMBearerIpConfig *mm_bearer_ip_config_new (void);
+MMBearerIpConfig *mm_bearer_ip_config_new_from_dictionary (GVariant *dictionary,
+ GError **error);
+
+MMBearerIpConfig *mm_bearer_ip_config_dup (MMBearerIpConfig *orig);
+
+MMBearerIpMethod mm_bearer_ip_config_get_method (MMBearerIpConfig *self);
+const gchar *mm_bearer_ip_config_get_address (MMBearerIpConfig *self);
+guint mm_bearer_ip_config_get_prefix (MMBearerIpConfig *self);
+const gchar **mm_bearer_ip_config_get_dns (MMBearerIpConfig *self);
+const gchar *mm_bearer_ip_config_get_gateway (MMBearerIpConfig *self);
+
+void mm_bearer_ip_config_set_method (MMBearerIpConfig *self,
+ MMBearerIpMethod ip_method);
+void mm_bearer_ip_config_set_address (MMBearerIpConfig *self,
+ const gchar *address);
+void mm_bearer_ip_config_set_prefix (MMBearerIpConfig *self,
+ guint prefix);
+void mm_bearer_ip_config_set_dns (MMBearerIpConfig *self,
+ const gchar **dns);
+void mm_bearer_ip_config_set_gateway (MMBearerIpConfig *self,
+ const gchar *gateway);
+
+GVariant *mm_bearer_ip_config_get_dictionary (MMBearerIpConfig *self);
+
+G_END_DECLS
+
+#endif /* MM_BEARER_IP_CONFIG_H */
diff --git a/libmm-glib/mm-bearer-properties.c b/libmm-glib/mm-bearer-properties.c
new file mode 100644
index 00000000..ab7d4408
--- /dev/null
+++ b/libmm-glib/mm-bearer-properties.c
@@ -0,0 +1,513 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2011 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <string.h>
+
+#include "mm-errors-types.h"
+#include "mm-common-helpers.h"
+#include "mm-bearer-properties.h"
+
+G_DEFINE_TYPE (MMBearerProperties, mm_bearer_properties, G_TYPE_OBJECT);
+
+#define PROPERTY_APN "apn"
+#define PROPERTY_USER "user"
+#define PROPERTY_PASSWORD "password"
+#define PROPERTY_IP_TYPE "ip-type"
+#define PROPERTY_NUMBER "number"
+#define PROPERTY_ALLOW_ROAMING "allow-roaming"
+#define PROPERTY_RM_PROTOCOL "rm-protocol"
+
+struct _MMBearerPropertiesPrivate {
+ /* APN */
+ gchar *apn;
+ /* IP type */
+ MMBearerIpFamily ip_type;
+ /* Number */
+ gchar *number;
+ /* User */
+ gchar *user;
+ /* Password */
+ gchar *password;
+ /* Roaming allowance */
+ gboolean allow_roaming_set;
+ gboolean allow_roaming;
+ /* Protocol of the Rm interface */
+ MMModemCdmaRmProtocol rm_protocol;
+};
+
+/*****************************************************************************/
+
+void
+mm_bearer_properties_set_apn (MMBearerProperties *self,
+ const gchar *apn)
+{
+ g_return_if_fail (MM_IS_BEARER_PROPERTIES (self));
+
+ g_free (self->priv->apn);
+ self->priv->apn = g_strdup (apn);
+}
+
+void
+mm_bearer_properties_set_user (MMBearerProperties *self,
+ const gchar *user)
+{
+ g_return_if_fail (MM_IS_BEARER_PROPERTIES (self));
+
+ g_free (self->priv->user);
+ self->priv->user = g_strdup (user);
+}
+
+void
+mm_bearer_properties_set_password (MMBearerProperties *self,
+ const gchar *password)
+{
+ g_return_if_fail (MM_IS_BEARER_PROPERTIES (self));
+
+ g_free (self->priv->password);
+ self->priv->password = g_strdup (password);
+}
+
+void
+mm_bearer_properties_set_ip_type (MMBearerProperties *self,
+ MMBearerIpFamily ip_type)
+{
+ g_return_if_fail (MM_IS_BEARER_PROPERTIES (self));
+
+ self->priv->ip_type = ip_type;
+}
+
+void
+mm_bearer_properties_set_allow_roaming (MMBearerProperties *self,
+ gboolean allow_roaming)
+{
+ g_return_if_fail (MM_IS_BEARER_PROPERTIES (self));
+
+ self->priv->allow_roaming = allow_roaming;
+ self->priv->allow_roaming_set = TRUE;
+}
+
+void
+mm_bearer_properties_set_number (MMBearerProperties *self,
+ const gchar *number)
+{
+ g_return_if_fail (MM_IS_BEARER_PROPERTIES (self));
+
+ g_free (self->priv->number);
+ self->priv->number = g_strdup (number);
+}
+
+void
+mm_bearer_properties_set_rm_protocol (MMBearerProperties *self,
+ MMModemCdmaRmProtocol protocol)
+{
+ g_return_if_fail (MM_IS_BEARER_PROPERTIES (self));
+
+ self->priv->rm_protocol = protocol;
+}
+
+/*****************************************************************************/
+
+const gchar *
+mm_bearer_properties_get_apn (MMBearerProperties *self)
+{
+ g_return_val_if_fail (MM_IS_BEARER_PROPERTIES (self), NULL);
+
+ return self->priv->apn;
+}
+
+const gchar *
+mm_bearer_properties_get_user (MMBearerProperties *self)
+{
+ g_return_val_if_fail (MM_IS_BEARER_PROPERTIES (self), NULL);
+
+ return self->priv->user;
+}
+
+const gchar *
+mm_bearer_properties_get_password (MMBearerProperties *self)
+{
+ g_return_val_if_fail (MM_IS_BEARER_PROPERTIES (self), NULL);
+
+ return self->priv->password;
+}
+
+MMBearerIpFamily
+mm_bearer_properties_get_ip_type (MMBearerProperties *self)
+{
+ g_return_val_if_fail (MM_IS_BEARER_PROPERTIES (self), MM_BEARER_IP_FAMILY_UNKNOWN);
+
+ return self->priv->ip_type;
+}
+
+gboolean
+mm_bearer_properties_get_allow_roaming (MMBearerProperties *self)
+{
+ g_return_val_if_fail (MM_IS_BEARER_PROPERTIES (self), FALSE);
+
+ return self->priv->allow_roaming;
+}
+
+const gchar *
+mm_bearer_properties_get_number (MMBearerProperties *self)
+{
+ g_return_val_if_fail (MM_IS_BEARER_PROPERTIES (self), NULL);
+
+ return self->priv->number;
+}
+
+MMModemCdmaRmProtocol
+mm_bearer_properties_get_rm_protocol (MMBearerProperties *self)
+{
+ g_return_val_if_fail (MM_IS_BEARER_PROPERTIES (self), MM_MODEM_CDMA_RM_PROTOCOL_UNKNOWN);
+
+ return self->priv->rm_protocol;
+}
+
+/*****************************************************************************/
+
+GVariant *
+mm_bearer_properties_get_dictionary (MMBearerProperties *self)
+{
+ GVariantBuilder builder;
+
+ /* We do allow NULL */
+ if (!self)
+ return NULL;
+
+ g_return_val_if_fail (MM_IS_BEARER_PROPERTIES (self), NULL);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+ if (self->priv->apn)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_APN,
+ g_variant_new_string (self->priv->apn));
+
+ if (self->priv->user)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_USER,
+ g_variant_new_string (self->priv->user));
+
+ if (self->priv->password)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_PASSWORD,
+ g_variant_new_string (self->priv->password));
+
+ if (self->priv->ip_type != MM_BEARER_IP_FAMILY_UNKNOWN)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_IP_TYPE,
+ g_variant_new_uint32 (self->priv->ip_type));
+
+ if (self->priv->number)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_NUMBER,
+ g_variant_new_string (self->priv->number));
+
+ if (self->priv->allow_roaming_set)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_ALLOW_ROAMING,
+ g_variant_new_boolean (self->priv->allow_roaming));
+
+ if (self->priv->rm_protocol)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_RM_PROTOCOL,
+ g_variant_new_uint32 (self->priv->rm_protocol));
+
+ return g_variant_ref_sink (g_variant_builder_end (&builder));
+}
+
+/*****************************************************************************/
+
+gboolean
+mm_bearer_properties_consume_string (MMBearerProperties *self,
+ const gchar *key,
+ const gchar *value,
+ GError **error)
+{
+ g_return_val_if_fail (MM_IS_BEARER_PROPERTIES (self), FALSE);
+
+ if (g_str_equal (key, PROPERTY_APN))
+ mm_bearer_properties_set_apn (self, value);
+ else if (g_str_equal (key, PROPERTY_USER))
+ mm_bearer_properties_set_user (self, value);
+ else if (g_str_equal (key, PROPERTY_PASSWORD))
+ mm_bearer_properties_set_password (self, value);
+ else if (g_str_equal (key, PROPERTY_IP_TYPE)) {
+ GError *inner_error = NULL;
+ MMBearerIpFamily ip_type;
+
+ ip_type = mm_common_get_ip_type_from_string (value, &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+ mm_bearer_properties_set_ip_type (self, ip_type);
+ } else if (g_str_equal (key, PROPERTY_ALLOW_ROAMING)) {
+ GError *inner_error = NULL;
+ gboolean allow_roaming;
+
+ allow_roaming = mm_common_get_boolean_from_string (value, &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+ mm_bearer_properties_set_allow_roaming (self, allow_roaming);
+ } else if (g_str_equal (key, PROPERTY_NUMBER))
+ mm_bearer_properties_set_number (self, value);
+ else if (g_str_equal (key, PROPERTY_RM_PROTOCOL)) {
+ GError *inner_error = NULL;
+ MMModemCdmaRmProtocol protocol;
+
+ protocol = mm_common_get_rm_protocol_from_string (value, &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+ mm_bearer_properties_set_rm_protocol (self, protocol);
+ } else {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid properties string, unexpected key '%s'",
+ key);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+typedef struct {
+ MMBearerProperties *properties;
+ GError *error;
+} ParseKeyValueContext;
+
+static gboolean
+key_value_foreach (const gchar *key,
+ const gchar *value,
+ ParseKeyValueContext *ctx)
+{
+ return mm_bearer_properties_consume_string (ctx->properties,
+ key,
+ value,
+ &ctx->error);
+}
+
+MMBearerProperties *
+mm_bearer_properties_new_from_string (const gchar *str,
+ GError **error)
+{
+ ParseKeyValueContext ctx;
+
+ ctx.error = NULL;
+ ctx.properties = mm_bearer_properties_new ();
+
+ mm_common_parse_key_value_string (str,
+ &ctx.error,
+ (MMParseKeyValueForeachFn)key_value_foreach,
+ &ctx);
+ /* If error, destroy the object */
+ if (ctx.error) {
+ g_propagate_error (error, ctx.error);
+ g_object_unref (ctx.properties);
+ ctx.properties = NULL;
+ }
+
+ return ctx.properties;
+}
+
+/*****************************************************************************/
+
+gboolean
+mm_bearer_properties_consume_variant (MMBearerProperties *properties,
+ const gchar *key,
+ GVariant *value,
+ GError **error)
+{
+ g_return_val_if_fail (MM_IS_BEARER_PROPERTIES (properties), FALSE);
+
+ if (g_str_equal (key, PROPERTY_APN))
+ mm_bearer_properties_set_apn (
+ properties,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_USER))
+ mm_bearer_properties_set_user (
+ properties,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_PASSWORD))
+ mm_bearer_properties_set_password (
+ properties,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_IP_TYPE))
+ mm_bearer_properties_set_ip_type (
+ properties,
+ g_variant_get_uint32 (value));
+ else if (g_str_equal (key, PROPERTY_NUMBER))
+ mm_bearer_properties_set_number (
+ properties,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_ALLOW_ROAMING))
+ mm_bearer_properties_set_allow_roaming (
+ properties,
+ g_variant_get_boolean (value));
+ else {
+ /* Set error */
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid properties dictionary, unexpected key '%s'",
+ key);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+MMBearerProperties *
+mm_bearer_properties_new_from_dictionary (GVariant *dictionary,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ GVariantIter iter;
+ gchar *key;
+ GVariant *value;
+ MMBearerProperties *properties;
+
+ properties = mm_bearer_properties_new ();
+ if (!dictionary)
+ return properties;
+
+ if (!g_variant_is_of_type (dictionary, G_VARIANT_TYPE ("a{sv}"))) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create Bearer properties from dictionary: "
+ "invalid variant type received");
+ g_object_unref (properties);
+ return NULL;
+ }
+
+ g_variant_iter_init (&iter, dictionary);
+ while (!inner_error &&
+ g_variant_iter_next (&iter, "{sv}", &key, &value)) {
+ mm_bearer_properties_consume_variant (properties,
+ key,
+ value,
+ &inner_error);
+ g_free (key);
+ g_variant_unref (value);
+ }
+
+ /* If error, destroy the object */
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ g_object_unref (properties);
+ properties = NULL;
+ }
+
+ return properties;
+}
+
+/*****************************************************************************/
+
+MMBearerProperties *
+mm_bearer_properties_dup (MMBearerProperties *orig)
+{
+ GVariant *dict;
+ MMBearerProperties *copy;
+ GError *error = NULL;
+
+ g_return_val_if_fail (MM_IS_BEARER_PROPERTIES (orig), NULL);
+
+ dict = mm_bearer_properties_get_dictionary (orig);
+ copy = mm_bearer_properties_new_from_dictionary (dict, &error);
+ g_assert_no_error (error);
+ g_variant_unref (dict);
+
+ return copy;
+}
+
+/*****************************************************************************/
+
+gboolean
+mm_bearer_properties_cmp (MMBearerProperties *a,
+ MMBearerProperties *b)
+{
+ return ((!g_strcmp0 (a->priv->apn, b->priv->apn)) &&
+ (a->priv->ip_type == b->priv->ip_type) &&
+ (!g_strcmp0 (a->priv->number, b->priv->number)) &&
+ (!g_strcmp0 (a->priv->user, b->priv->user)) &&
+ (!g_strcmp0 (a->priv->password, b->priv->password)) &&
+ (a->priv->allow_roaming == b->priv->allow_roaming) &&
+ (a->priv->allow_roaming_set == b->priv->allow_roaming_set) &&
+ (a->priv->rm_protocol == b->priv->rm_protocol));
+}
+
+/*****************************************************************************/
+
+MMBearerProperties *
+mm_bearer_properties_new (void)
+{
+ return (MM_BEARER_PROPERTIES (
+ g_object_new (MM_TYPE_BEARER_PROPERTIES, NULL)));
+}
+
+static void
+mm_bearer_properties_init (MMBearerProperties *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
+ MM_TYPE_BEARER_PROPERTIES,
+ MMBearerPropertiesPrivate);
+
+ /* Some defaults */
+ self->priv->allow_roaming = TRUE;
+ self->priv->rm_protocol = MM_MODEM_CDMA_RM_PROTOCOL_UNKNOWN;
+
+ /* At some point in the future, this default should probably be changed
+ * to IPV4V6. However, presently support for this PDP type is rare. An
+ * even better approach would likely be to query which PDP types the
+ * modem supports (using AT+CGDCONT=?), and set the default accordingly
+ */
+ self->priv->ip_type = MM_BEARER_IP_FAMILY_IPV4;
+}
+
+static void
+finalize (GObject *object)
+{
+ MMBearerProperties *self = MM_BEARER_PROPERTIES (object);
+
+ g_free (self->priv->apn);
+ g_free (self->priv->user);
+ g_free (self->priv->password);
+ g_free (self->priv->number);
+
+ G_OBJECT_CLASS (mm_bearer_properties_parent_class)->finalize (object);
+}
+
+static void
+mm_bearer_properties_class_init (MMBearerPropertiesClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMBearerPropertiesPrivate));
+
+ object_class->finalize = finalize;
+}
diff --git a/libmm-glib/mm-bearer-properties.h b/libmm-glib/mm-bearer-properties.h
new file mode 100644
index 00000000..8272e6b6
--- /dev/null
+++ b/libmm-glib/mm-bearer-properties.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2011 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#ifndef MM_BEARER_PROPERTIES_H
+#define MM_BEARER_PROPERTIES_H
+
+#include <ModemManager.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MM_TYPE_BEARER_PROPERTIES (mm_bearer_properties_get_type ())
+#define MM_BEARER_PROPERTIES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BEARER_PROPERTIES, MMBearerProperties))
+#define MM_BEARER_PROPERTIES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BEARER_PROPERTIES, MMBearerPropertiesClass))
+#define MM_IS_BEARER_PROPERTIES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BEARER_PROPERTIES))
+#define MM_IS_BEARER_PROPERTIES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BEARER_PROPERTIES))
+#define MM_BEARER_PROPERTIES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BEARER_PROPERTIES, MMBearerPropertiesClass))
+
+typedef struct _MMBearerProperties MMBearerProperties;
+typedef struct _MMBearerPropertiesClass MMBearerPropertiesClass;
+typedef struct _MMBearerPropertiesPrivate MMBearerPropertiesPrivate;
+
+struct _MMBearerProperties {
+ GObject parent;
+ MMBearerPropertiesPrivate *priv;
+};
+
+struct _MMBearerPropertiesClass {
+ GObjectClass parent;
+};
+
+GType mm_bearer_properties_get_type (void);
+
+MMBearerProperties *mm_bearer_properties_new (void);
+MMBearerProperties *mm_bearer_properties_new_from_string (const gchar *str,
+ GError **error);
+MMBearerProperties *mm_bearer_properties_new_from_dictionary (GVariant *dictionary,
+ GError **error);
+
+MMBearerProperties *mm_bearer_properties_dup (MMBearerProperties *orig);
+
+void mm_bearer_properties_set_apn (MMBearerProperties *properties,
+ const gchar *apn);
+void mm_bearer_properties_set_user (MMBearerProperties *properties,
+ const gchar *user);
+void mm_bearer_properties_set_password (MMBearerProperties *properties,
+ const gchar *password);
+void mm_bearer_properties_set_ip_type (MMBearerProperties *properties,
+ MMBearerIpFamily ip_type);
+void mm_bearer_properties_set_allow_roaming (MMBearerProperties *properties,
+ gboolean allow_roaming);
+void mm_bearer_properties_set_number (MMBearerProperties *properties,
+ const gchar *number);
+void mm_bearer_properties_set_rm_protocol (MMBearerProperties *properties,
+ MMModemCdmaRmProtocol protocol);
+
+const gchar *mm_bearer_properties_get_apn (MMBearerProperties *properties);
+const gchar *mm_bearer_properties_get_user (MMBearerProperties *properties);
+const gchar *mm_bearer_properties_get_password (MMBearerProperties *properties);
+MMBearerIpFamily mm_bearer_properties_get_ip_type (MMBearerProperties *properties);
+gboolean mm_bearer_properties_get_allow_roaming (MMBearerProperties *properties);
+const gchar *mm_bearer_properties_get_number (MMBearerProperties *properties);
+MMModemCdmaRmProtocol mm_bearer_properties_get_rm_protocol (MMBearerProperties *properties);
+
+gboolean mm_bearer_properties_consume_string (MMBearerProperties *self,
+ const gchar *key,
+ const gchar *value,
+ GError **error);
+
+gboolean mm_bearer_properties_consume_variant (MMBearerProperties *self,
+ const gchar *key,
+ GVariant *value,
+ GError **error);
+
+GVariant *mm_bearer_properties_get_dictionary (MMBearerProperties *self);
+
+gboolean mm_bearer_properties_cmp (MMBearerProperties *a,
+ MMBearerProperties *b);
+
+G_END_DECLS
+
+#endif /* MM_BEARER_PROPERTIES_H */
diff --git a/libmm-glib/mm-common-helpers.c b/libmm-glib/mm-common-helpers.c
new file mode 100644
index 00000000..552881e5
--- /dev/null
+++ b/libmm-glib/mm-common-helpers.c
@@ -0,0 +1,901 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2010 - 2012 Red Hat, Inc.
+ * Copyright (C) 2011 - 2012 Google, Inc.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <gio/gio.h>
+
+#include <ModemManager.h>
+
+#include "mm-enums-types.h"
+#include "mm-errors-types.h"
+#include "mm-common-helpers.h"
+
+gchar *
+mm_common_build_bands_string (const MMModemBand *bands,
+ guint n_bands)
+{
+ gboolean first = TRUE;
+ GString *str;
+ guint i;
+
+ if (!bands || !n_bands)
+ return g_strdup ("none");
+
+ str = g_string_new ("");
+ for (i = 0; i < n_bands; i++) {
+ g_string_append_printf (str, "%s%s",
+ first ? "" : ", ",
+ mm_modem_band_get_string (bands[i]));
+
+ if (first)
+ first = FALSE;
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+gchar *
+mm_common_build_sms_storages_string (const MMSmsStorage *storages,
+ guint n_storages)
+{
+ gboolean first = TRUE;
+ GString *str;
+ guint i;
+
+ if (!storages || !n_storages)
+ return g_strdup ("none");
+
+ str = g_string_new ("");
+ for (i = 0; i < n_storages; i++) {
+ g_string_append_printf (str, "%s%s",
+ first ? "" : ", ",
+ mm_sms_storage_get_string (storages[i]));
+
+ if (first)
+ first = FALSE;
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+GArray *
+mm_common_sms_storages_variant_to_garray (GVariant *variant)
+{
+ GArray *array = NULL;
+
+ if (variant) {
+ GVariantIter iter;
+ guint n;
+
+ g_variant_iter_init (&iter, variant);
+ n = g_variant_iter_n_children (&iter);
+
+ if (n > 0) {
+ guint32 storage;
+
+ array = g_array_sized_new (FALSE, FALSE, sizeof (MMSmsStorage), n);
+ while (g_variant_iter_loop (&iter, "u", &storage))
+ g_array_append_val (array, storage);
+ }
+ }
+
+ return array;
+}
+
+MMSmsStorage *
+mm_common_sms_storages_variant_to_array (GVariant *variant,
+ guint *n_storages)
+{
+ GArray *array;
+
+ array = mm_common_sms_storages_variant_to_garray (variant);
+ if (n_storages)
+ *n_storages = array->len;
+ return (MMSmsStorage *) g_array_free (array, FALSE);
+}
+
+GVariant *
+mm_common_sms_storages_array_to_variant (const MMSmsStorage *storages,
+ guint n_storages)
+{
+ GVariantBuilder builder;
+ guint i;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("au"));
+
+ for (i = 0; i < n_storages; i++)
+ g_variant_builder_add_value (&builder,
+ g_variant_new_uint32 ((guint32)storages[i]));
+ return g_variant_builder_end (&builder);
+}
+
+GVariant *
+mm_common_sms_storages_garray_to_variant (GArray *array)
+{
+ if (array)
+ return mm_common_sms_storages_array_to_variant ((const MMSmsStorage *)array->data,
+ array->len);
+
+ return mm_common_sms_storages_array_to_variant (NULL, 0);
+}
+
+MMModemMode
+mm_common_get_modes_from_string (const gchar *str,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ MMModemMode modes;
+ gchar **mode_strings;
+ GFlagsClass *flags_class;
+
+ modes = MM_MODEM_MODE_NONE;
+
+ flags_class = G_FLAGS_CLASS (g_type_class_ref (MM_TYPE_MODEM_MODE));
+ mode_strings = g_strsplit (str, "|", -1);
+
+ if (mode_strings) {
+ guint i;
+
+ for (i = 0; mode_strings[i]; i++) {
+ guint j;
+ gboolean found = FALSE;
+
+ for (j = 0; flags_class->values[j].value_nick; j++) {
+ if (!g_ascii_strcasecmp (mode_strings[i], flags_class->values[j].value_nick)) {
+ modes |= flags_class->values[j].value;
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ inner_error = g_error_new (
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Couldn't match '%s' with a valid MMModemMode value",
+ mode_strings[i]);
+ break;
+ }
+ }
+ }
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ modes = MM_MODEM_MODE_NONE;
+ }
+
+ g_type_class_unref (flags_class);
+ g_strfreev (mode_strings);
+ return modes;
+}
+
+void
+mm_common_get_bands_from_string (const gchar *str,
+ MMModemBand **bands,
+ guint *n_bands,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ GArray *array;
+ gchar **band_strings;
+ GEnumClass *enum_class;
+
+ array = g_array_new (FALSE, FALSE, sizeof (MMModemBand));
+
+ enum_class = G_ENUM_CLASS (g_type_class_ref (MM_TYPE_MODEM_BAND));
+ band_strings = g_strsplit (str, "|", -1);
+
+ if (band_strings) {
+ guint i;
+
+ for (i = 0; band_strings[i]; i++) {
+ guint j;
+ gboolean found = FALSE;
+
+ for (j = 0; enum_class->values[j].value_nick; j++) {
+ if (!g_ascii_strcasecmp (band_strings[i], enum_class->values[j].value_nick)) {
+ g_array_append_val (array, enum_class->values[j].value);
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Couldn't match '%s' with a valid MMModemBand value",
+ band_strings[i]);
+ break;
+ }
+ }
+ }
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ g_array_free (array, TRUE);
+ *n_bands = 0;
+ *bands = NULL;
+ } else {
+ if (!array->len) {
+ GEnumValue *value;
+
+ value = g_enum_get_value (enum_class, MM_MODEM_BAND_UNKNOWN);
+ g_array_append_val (array, value->value);
+ }
+
+ *n_bands = array->len;
+ *bands = (MMModemBand *)g_array_free (array, FALSE);
+ }
+
+ g_type_class_unref (enum_class);
+ g_strfreev (band_strings);
+}
+
+GArray *
+mm_common_bands_variant_to_garray (GVariant *variant)
+{
+ GArray *array = NULL;
+
+ if (variant) {
+ GVariantIter iter;
+ guint n;
+
+ g_variant_iter_init (&iter, variant);
+ n = g_variant_iter_n_children (&iter);
+
+ if (n > 0) {
+ guint32 band;
+
+ array = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), n);
+ while (g_variant_iter_loop (&iter, "u", &band))
+ g_array_append_val (array, band);
+ }
+ }
+
+ /* If nothing set, fallback to default */
+ if (!array) {
+ guint32 band = MM_MODEM_BAND_UNKNOWN;
+
+ array = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 1);
+ g_array_append_val (array, band);
+ }
+
+ return array;
+}
+
+MMModemBand *
+mm_common_bands_variant_to_array (GVariant *variant,
+ guint *n_bands)
+{
+ GArray *array;
+
+ array = mm_common_bands_variant_to_garray (variant);
+ if (n_bands)
+ *n_bands = array->len;
+ return (MMModemBand *) g_array_free (array, FALSE);
+}
+
+GVariant *
+mm_common_bands_array_to_variant (const MMModemBand *bands,
+ guint n_bands)
+{
+ if (n_bands > 0) {
+ GVariantBuilder builder;
+ guint i;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("au"));
+
+ for (i = 0; i < n_bands; i++)
+ g_variant_builder_add_value (&builder,
+ g_variant_new_uint32 ((guint32)bands[i]));
+ return g_variant_builder_end (&builder);
+ }
+
+ return mm_common_build_bands_unknown ();
+}
+
+GVariant *
+mm_common_bands_garray_to_variant (GArray *array)
+{
+ if (array)
+ return mm_common_bands_array_to_variant ((const MMModemBand *)array->data,
+ array->len);
+
+ return mm_common_bands_array_to_variant (NULL, 0);
+}
+
+static guint
+cmp_band (MMModemBand *a, MMModemBand *b)
+{
+ return (*a - *b);
+}
+
+gboolean
+mm_common_bands_garray_cmp (GArray *a, GArray *b)
+{
+ GArray *dup_a;
+ GArray *dup_b;
+ guint i;
+ gboolean different;
+
+ if (a->len != b->len)
+ return FALSE;
+
+ dup_a = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), a->len);
+ g_array_append_vals (dup_a, a->data, a->len);
+
+ dup_b = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), b->len);
+ g_array_append_vals (dup_b, b->data, b->len);
+
+ g_array_sort (dup_a, (GCompareFunc)cmp_band);
+ g_array_sort (dup_b, (GCompareFunc)cmp_band);
+
+ different = FALSE;
+ for (i = 0; !different && i < a->len; i++) {
+ if (g_array_index (dup_a, MMModemBand, i) != g_array_index (dup_b, MMModemBand, i))
+ different = TRUE;
+ }
+
+ g_array_unref (dup_a);
+ g_array_unref (dup_b);
+
+ return !different;
+}
+
+gboolean
+mm_common_get_boolean_from_string (const gchar *value,
+ GError **error)
+{
+ if (!g_ascii_strcasecmp (value, "true") || g_str_equal (value, "1"))
+ return TRUE;
+
+ if (g_ascii_strcasecmp (value, "false") && g_str_equal (value, "0"))
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot get boolean from string '%s'", value);
+
+ return FALSE;
+}
+
+MMModemCdmaRmProtocol
+mm_common_get_rm_protocol_from_string (const gchar *str,
+ GError **error)
+{
+ GEnumClass *enum_class;
+ guint i;
+
+ enum_class = G_ENUM_CLASS (g_type_class_ref (MM_TYPE_MODEM_CDMA_RM_PROTOCOL));
+
+ for (i = 0; enum_class->values[i].value_nick; i++) {
+ if (!g_ascii_strcasecmp (str, enum_class->values[i].value_nick))
+ return enum_class->values[i].value;
+ }
+
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Couldn't match '%s' with a valid MMModemCdmaRmProtocol value",
+ str);
+ return MM_MODEM_CDMA_RM_PROTOCOL_UNKNOWN;
+}
+
+MMBearerIpFamily
+mm_common_get_ip_type_from_string (const gchar *str,
+ GError **error)
+{
+ GEnumClass *enum_class;
+ guint i;
+
+ enum_class = G_ENUM_CLASS (g_type_class_ref (MM_TYPE_BEARER_IP_FAMILY));
+
+ for (i = 0; enum_class->values[i].value_nick; i++) {
+ if (!g_ascii_strcasecmp (str, enum_class->values[i].value_nick))
+ return enum_class->values[i].value;
+ }
+
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Couldn't match '%s' with a valid MMBearerIpFamily value",
+ str);
+ return MM_BEARER_IP_FAMILY_UNKNOWN;
+}
+
+MMSmsStorage
+mm_common_get_sms_storage_from_string (const gchar *str,
+ GError **error)
+{
+ GEnumClass *enum_class;
+ guint i;
+
+ enum_class = G_ENUM_CLASS (g_type_class_ref (MM_TYPE_SMS_STORAGE));
+
+ for (i = 0; enum_class->values[i].value_nick; i++) {
+ if (!g_ascii_strcasecmp (str, enum_class->values[i].value_nick))
+ return enum_class->values[i].value;
+ }
+
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Couldn't match '%s' with a valid MMSmsStorage value",
+ str);
+ return MM_SMS_STORAGE_UNKNOWN;
+}
+
+GVariant *
+mm_common_build_bands_unknown (void)
+{
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("au"));
+ g_variant_builder_add_value (&builder,
+ g_variant_new_uint32 (MM_MODEM_BAND_UNKNOWN));
+ return g_variant_builder_end (&builder);
+}
+
+GVariant *
+mm_common_build_bands_any (void)
+{
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("au"));
+ g_variant_builder_add_value (&builder,
+ g_variant_new_uint32 (MM_MODEM_BAND_ANY));
+ return g_variant_builder_end (&builder);
+}
+
+/* Expecting input as:
+ * key1=string,key2=true,key3=false...
+ * Strings may also be passed enclosed between double or single quotes, like:
+ * key1="this is a string", key2='and so is this'
+ */
+gboolean
+mm_common_parse_key_value_string (const gchar *str,
+ GError **error,
+ MMParseKeyValueForeachFn callback,
+ gpointer user_data)
+{
+ GError *inner_error = NULL;
+ gchar *dup, *p, *key, *key_end, *value, *value_end, quote;
+
+ g_return_val_if_fail (callback != NULL, FALSE);
+ g_return_val_if_fail (str != NULL, FALSE);
+
+ /* Allow empty strings, we'll just return with success */
+ while (g_ascii_isspace (*str))
+ str++;
+ if (!str[0])
+ return TRUE;
+
+ dup = g_strdup (str);
+ p = dup;
+
+ while (TRUE) {
+ gboolean keep_iteration = FALSE;
+
+ /* Skip leading spaces */
+ while (g_ascii_isspace (*p))
+ p++;
+
+ /* Key start */
+ key = p;
+ if (!g_ascii_isalnum (*key)) {
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Key must start with alpha/num, starts with '%c'",
+ *key);
+ break;
+ }
+
+ /* Key end */
+ while (g_ascii_isalnum (*p) || (*p == '-') || (*p == '_'))
+ p++;
+ key_end = p;
+ if (key_end == key) {
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Couldn't find a proper key");
+ break;
+ }
+
+ /* Skip whitespaces, if any */
+ while (g_ascii_isspace (*p))
+ p++;
+
+ /* Equal sign must be here */
+ if (*p != '=') {
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Couldn't find equal sign separator");
+ break;
+ }
+ /* Skip the equal */
+ p++;
+
+ /* Skip whitespaces, if any */
+ while (g_ascii_isspace (*p))
+ p++;
+
+ /* Do we have a quote-enclosed string? */
+ if (*p == '\"' || *p == '\'') {
+ quote = *p;
+ /* Skip the quote */
+ p++;
+ /* Value start */
+ value = p;
+ /* Find the closing quote */
+ p = strchr (p, quote);
+ if (!p) {
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Unmatched quotes in string value");
+ break;
+ }
+
+ /* Value end */
+ value_end = p;
+ /* Skip the quote */
+ p++;
+ } else {
+ /* Value start */
+ value = p;
+
+ /* Value end */
+ while ((*p != ',') && (*p != '\0') && !g_ascii_isspace (*p))
+ p++;
+ value_end = p;
+ }
+
+ /* Note that we allow value == value_end here */
+
+ /* Skip whitespaces, if any */
+ while (g_ascii_isspace (*p))
+ p++;
+
+ /* If a comma is found, we should keep the iteration */
+ if (*p == ',') {
+ /* skip the comma */
+ p++;
+ keep_iteration = TRUE;
+ }
+
+ /* Got key and value, prepare them and run the callback */
+ *value_end = '\0';
+ *key_end = '\0';
+ if (!callback (key, value, user_data)) {
+ /* We were told to abort */
+ break;
+ }
+
+ if (keep_iteration)
+ continue;
+
+ /* Check if no more key/value pairs expected */
+ if (*p == '\0')
+ break;
+
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Unexpected content (%s) after value",
+ p);
+ break;
+ }
+
+ g_free (dup);
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+gboolean
+mm_get_int_from_str (const gchar *str,
+ gint *out)
+{
+ glong num;
+
+ if (!str || !str[0])
+ return FALSE;
+
+ for (num = 0; str[num]; num++) {
+ if (str[num] != '-' && !g_ascii_isdigit (str[num]))
+ return FALSE;
+ }
+
+ errno = 0;
+ num = strtol (str, NULL, 10);
+ if (!errno && num >= G_MININT && num <= G_MAXINT) {
+ *out = (gint)num;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gboolean
+mm_get_int_from_match_info (GMatchInfo *match_info,
+ guint32 match_index,
+ gint *out)
+{
+ gchar *s;
+ gboolean ret;
+
+ s = g_match_info_fetch (match_info, match_index);
+ g_return_val_if_fail (s != NULL, FALSE);
+
+ ret = mm_get_int_from_str (s, out);
+ g_free (s);
+
+ return ret;
+}
+
+gboolean
+mm_get_uint_from_str (const gchar *str,
+ guint *out)
+{
+ gulong num;
+
+ if (!str || !str[0])
+ return FALSE;
+
+ for (num = 0; str[num]; num++) {
+ if (!g_ascii_isdigit (str[num]))
+ return FALSE;
+ }
+
+ errno = 0;
+ num = strtoul (str, NULL, 10);
+ if (!errno && num <= G_MAXUINT) {
+ *out = (guint)num;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gboolean
+mm_get_uint_from_match_info (GMatchInfo *match_info,
+ guint32 match_index,
+ guint *out)
+{
+ gchar *s;
+ gboolean ret;
+
+ s = g_match_info_fetch (match_info, match_index);
+ g_return_val_if_fail (s != NULL, FALSE);
+
+ ret = mm_get_uint_from_str (s, out);
+ g_free (s);
+
+ return ret;
+}
+
+gboolean
+mm_get_double_from_str (const gchar *str,
+ gdouble *out)
+{
+ gdouble num;
+ guint i;
+
+ if (!str || !str[0])
+ return FALSE;
+
+ for (i = 0; str[i]; i++) {
+ /* we don't really expect numbers in scientific notation, so
+ * don't bother looking for exponents and such */
+ if (str[i] != '-' &&
+ str[i] != '.' &&
+ !g_ascii_isdigit (str[i]))
+ return FALSE;
+ }
+
+ errno = 0;
+ num = strtod (str, NULL);
+ if (!errno) {
+ *out = num;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gboolean
+mm_get_double_from_match_info (GMatchInfo *match_info,
+ guint32 match_index,
+ gdouble *out)
+{
+ gchar *s;
+ gboolean ret;
+
+ s = g_match_info_fetch (match_info, match_index);
+ g_return_val_if_fail (s != NULL, FALSE);
+
+ ret = mm_get_double_from_str (s, out);
+ g_free (s);
+
+ return ret;
+}
+
+gchar *
+mm_get_string_unquoted_from_match_info (GMatchInfo *match_info,
+ guint32 match_index)
+{
+ gchar *str;
+ gsize len;
+
+ str = g_match_info_fetch (match_info, match_index);
+ if (!str)
+ return NULL;
+
+ len = strlen (str);
+
+ /* Unquote the item if needed */
+ if ((len >= 2) && (str[0] == '"') && (str[len - 1] == '"')) {
+ str[0] = ' ';
+ str[len - 1] = ' ';
+ str = g_strstrip (str);
+ }
+
+ if (!str[0]) {
+ g_free (str);
+ return NULL;
+ }
+
+ return str;
+}
+
+/*****************************************************************************/
+
+const gchar *
+mm_sms_delivery_state_get_string_extended (guint delivery_state)
+{
+ if (delivery_state > 0x02 && delivery_state < 0x20) {
+ if (delivery_state < 0x10)
+ return "completed-reason-reserved";
+ else
+ return "completed-sc-specific-reason";
+ }
+
+ if (delivery_state > 0x25 && delivery_state < 0x40) {
+ if (delivery_state < 0x30)
+ return "temporary-error-reason-reserved";
+ else
+ return "temporary-error-sc-specific-reason";
+ }
+
+ if (delivery_state > 0x49 && delivery_state < 0x60) {
+ if (delivery_state < 0x50)
+ return "error-reason-reserved";
+ else
+ return "error-sc-specific-reason";
+ }
+
+ if (delivery_state > 0x65 && delivery_state < 0x80) {
+ if (delivery_state < 0x70)
+ return "temporary-fatal-error-reason-reserved";
+ else
+ return "temporary-fatal-error-sc-specific-reason";
+ }
+
+ if (delivery_state >= 0x80 && delivery_state < 0x100)
+ return "unknown-reason-reserved";
+
+ if (delivery_state >= 0x100)
+ return "unknown";
+
+ /* Otherwise, use the MMSmsDeliveryState enum as we can match the known
+ * value */
+ return mm_sms_delivery_state_get_string ((MMSmsDeliveryState)delivery_state);
+}
+
+/*****************************************************************************/
+
+/* From hostap, Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> */
+
+static gint
+hex2num (gchar c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+gint
+mm_utils_hex2byte (const gchar *hex)
+{
+ gint a, b;
+
+ a = hex2num (*hex++);
+ if (a < 0)
+ return -1;
+ b = hex2num (*hex++);
+ if (b < 0)
+ return -1;
+ return (a << 4) | b;
+}
+
+gchar *
+mm_utils_hexstr2bin (const gchar *hex, gsize *out_len)
+{
+ const gchar *ipos = hex;
+ gchar *buf = NULL;
+ gsize i;
+ gint a;
+ gchar *opos;
+ gsize len;
+
+ len = strlen (hex);
+
+ /* Length must be a multiple of 2 */
+ g_return_val_if_fail ((len % 2) == 0, NULL);
+
+ opos = buf = g_malloc0 ((len / 2) + 1);
+ for (i = 0; i < len; i += 2) {
+ a = mm_utils_hex2byte (ipos);
+ if (a < 0) {
+ g_free (buf);
+ return NULL;
+ }
+ *opos++ = a;
+ ipos += 2;
+ }
+ *out_len = len / 2;
+ return buf;
+}
+
+/* End from hostap */
+
+gchar *
+mm_utils_bin2hexstr (const guint8 *bin, gsize len)
+{
+ GString *ret;
+ gsize i;
+
+ g_return_val_if_fail (bin != NULL, NULL);
+
+ ret = g_string_sized_new (len * 2 + 1);
+ for (i = 0; i < len; i++)
+ g_string_append_printf (ret, "%.2X", bin[i]);
+ return g_string_free (ret, FALSE);
+}
+
+gboolean
+mm_utils_check_for_single_value (guint32 value)
+{
+ gboolean found = FALSE;
+ guint32 i;
+
+ for (i = 1; i <= 32; i++) {
+ if (value & 0x1) {
+ if (found)
+ return FALSE; /* More than one bit set */
+ found = TRUE;
+ }
+ value >>= 1;
+ }
+
+ return TRUE;
+}
diff --git a/libmm-glib/mm-common-helpers.h b/libmm-glib/mm-common-helpers.h
new file mode 100644
index 00000000..3d5657d8
--- /dev/null
+++ b/libmm-glib/mm-common-helpers.h
@@ -0,0 +1,99 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2010 - 2012 Red Hat, Inc.
+ * Copyright (C) 2011 - 2012 Google, Inc.
+ * Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <glib.h>
+#include <ModemManager-enums.h>
+
+#ifndef MM_COMMON_HELPERS_H
+#define MM_COMMON_HELPERS_H
+
+gchar *mm_common_build_bands_string (const MMModemBand *bands,
+ guint n_bands);
+
+gchar *mm_common_build_sms_storages_string (const MMSmsStorage *storages,
+ guint n_storages);
+
+MMModemMode mm_common_get_modes_from_string (const gchar *str,
+ GError **error);
+void mm_common_get_bands_from_string (const gchar *str,
+ MMModemBand **bands,
+ guint *n_bands,
+ GError **error);
+gboolean mm_common_get_boolean_from_string (const gchar *value,
+ GError **error);
+MMModemCdmaRmProtocol mm_common_get_rm_protocol_from_string (const gchar *str,
+ GError **error);
+MMBearerIpFamily mm_common_get_ip_type_from_string (const gchar *str,
+ GError **error);
+MMSmsStorage mm_common_get_sms_storage_from_string (const gchar *str,
+ GError **error);
+
+GArray *mm_common_sms_storages_variant_to_garray (GVariant *variant);
+MMSmsStorage *mm_common_sms_storages_variant_to_array (GVariant *variant,
+ guint *n_storages);
+GVariant *mm_common_sms_storages_array_to_variant (const MMSmsStorage *storages,
+ guint n_storages);
+GVariant *mm_common_sms_storages_garray_to_variant (GArray *array);
+
+GArray *mm_common_bands_variant_to_garray (GVariant *variant);
+MMModemBand *mm_common_bands_variant_to_array (GVariant *variant,
+ guint *n_bands);
+GVariant *mm_common_bands_array_to_variant (const MMModemBand *bands,
+ guint n_bands);
+GVariant *mm_common_bands_garray_to_variant (GArray *array);
+
+GVariant *mm_common_build_bands_any (void);
+GVariant *mm_common_build_bands_unknown (void);
+
+gboolean mm_common_bands_garray_cmp (GArray *a, GArray *b);
+
+typedef gboolean (*MMParseKeyValueForeachFn) (const gchar *key,
+ const gchar *value,
+ gpointer user_data);
+gboolean mm_common_parse_key_value_string (const gchar *str,
+ GError **error,
+ MMParseKeyValueForeachFn callback,
+ gpointer user_data);
+
+/* Common parsers */
+gboolean mm_get_int_from_str (const gchar *str,
+ gint *out);
+gboolean mm_get_int_from_match_info (GMatchInfo *match_info,
+ guint32 match_index,
+ gint *out);
+gboolean mm_get_uint_from_str (const gchar *str,
+ guint *out);
+gboolean mm_get_uint_from_match_info (GMatchInfo *match_info,
+ guint32 match_index,
+ guint *out);
+gboolean mm_get_double_from_str (const gchar *str,
+ gdouble *out);
+gboolean mm_get_double_from_match_info (GMatchInfo *match_info,
+ guint32 match_index,
+ gdouble *out);
+gchar *mm_get_string_unquoted_from_match_info (GMatchInfo *match_info,
+ guint32 match_index);
+
+const gchar *mm_sms_delivery_state_get_string_extended (guint delivery_state);
+
+gint mm_utils_hex2byte (const gchar *hex);
+gchar *mm_utils_hexstr2bin (const gchar *hex, gsize *out_len);
+gchar *mm_utils_bin2hexstr (const guint8 *bin, gsize len);
+
+gboolean mm_utils_check_for_single_value (guint32 value);
+
+#endif /* MM_COMMON_HELPERS_H */
diff --git a/libmm-glib/mm-firmware-properties.c b/libmm-glib/mm-firmware-properties.c
new file mode 100644
index 00000000..8ef8347b
--- /dev/null
+++ b/libmm-glib/mm-firmware-properties.c
@@ -0,0 +1,300 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Google Inc.
+ */
+
+#include <string.h>
+
+#include "mm-errors-types.h"
+#include "mm-common-helpers.h"
+#include "mm-firmware-properties.h"
+
+G_DEFINE_TYPE (MMFirmwareProperties, mm_firmware_properties, G_TYPE_OBJECT);
+
+#define PROPERTY_NAME "name"
+#define PROPERTY_VERSION "version"
+#define PROPERTY_IMAGE_TYPE "image-type"
+
+struct _MMFirmwarePropertiesPrivate {
+ /* Mandatory parameters */
+ MMFirmwareImageType image_type;
+ gchar *name;
+ gchar *version;
+};
+
+static MMFirmwareProperties *firmware_properties_new_empty (void);
+
+/*****************************************************************************/
+
+/**
+ * mm_firmware_properties_get_name:
+ * @self: A #MMFirmwareProperties.
+ *
+ * Gets the unique name of the firmare image.
+ *
+ * Returns: (transfer none): The name of the image. Do not free the returned value, it is owned by @self.
+ */
+const gchar *
+mm_firmware_properties_get_name (MMFirmwareProperties *self)
+{
+ g_return_val_if_fail (MM_IS_FIRMWARE_PROPERTIES (self), NULL);
+
+ return self->priv->name;
+}
+
+/**
+ * mm_firmware_properties_get_version:
+ * @self: A #MMFirmwareProperties.
+ *
+ * Gets the version string of the firmare image.
+ *
+ * Returns: (transfer none): The version of the image. Do not free the returned value, it is owned by @self.
+ */
+const gchar *
+mm_firmware_properties_get_version (MMFirmwareProperties *self)
+{
+ g_return_val_if_fail (MM_IS_FIRMWARE_PROPERTIES (self), NULL);
+
+ return self->priv->version;
+}
+
+/**
+ * mm_firmware_properties_get_image_type:
+ * @self: A #MMFirmwareProperties.
+ *
+ * Gets the type of the firmare image.
+ *
+ * Returns: A #MMFirmwareImageType specifying The type of the image.
+ */
+MMFirmwareImageType
+mm_firmware_properties_get_image_type (MMFirmwareProperties *self)
+{
+ g_return_val_if_fail (MM_IS_FIRMWARE_PROPERTIES (self), MM_FIRMWARE_IMAGE_TYPE_UNKNOWN);
+
+ return self->priv->image_type;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_firmware_properties_get_dictionary:
+ * @self: A #MMFirmwareProperties.
+ *
+ * Gets a variant dictionary with the contents of @self.
+ *
+ * Returns: (transfer full): A dictionary with the image properties. The returned value should be freed with g_variant_unref().
+ */
+GVariant *
+mm_firmware_properties_get_dictionary (MMFirmwareProperties *self)
+{
+ GVariantBuilder builder;
+
+ g_return_val_if_fail (MM_IS_FIRMWARE_PROPERTIES (self), NULL);
+
+ /* We do allow NULL */
+ if (!self)
+ return NULL;
+
+ g_return_val_if_fail (MM_IS_FIRMWARE_PROPERTIES (self), NULL);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_NAME,
+ g_variant_new_string (self->priv->name));
+
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_VERSION,
+ g_variant_new_string (self->priv->version));
+
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_IMAGE_TYPE,
+ g_variant_new_uint32 (self->priv->image_type));
+
+ return g_variant_ref_sink (g_variant_builder_end (&builder));
+}
+
+/*****************************************************************************/
+
+static gboolean
+consume_variant (MMFirmwareProperties *self,
+ const gchar *key,
+ GVariant *value,
+ GError **error)
+{
+ if (g_str_equal (key, PROPERTY_NAME)) {
+ g_free (self->priv->name);
+ self->priv->name = g_variant_dup_string (value, NULL);
+ } else if (g_str_equal (key, PROPERTY_VERSION)) {
+ g_free (self->priv->version);
+ self->priv->version = g_variant_dup_string (value, NULL);
+ } else if (g_str_equal (key, PROPERTY_IMAGE_TYPE))
+ self->priv->image_type = g_variant_get_uint32 (value);
+ else {
+ /* Set error */
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid properties dictionary, unexpected key '%s'",
+ key);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * mm_firmware_properties_new_from_dictionary:
+ * @dictionary: A variant dictionary with the properties of the image.
+ * @error: Return location for error or %NULL.
+ *
+ * Creates a new #MMFirmwareProperties object with the properties exposed in
+ * the dictionary.
+ *
+ * Returns: (transfer full): A #MMFirmwareProperties or %NULL if @error is set. The returned value should be freed with g_object_unref().
+ */
+MMFirmwareProperties *
+mm_firmware_properties_new_from_dictionary (GVariant *dictionary,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ GVariantIter iter;
+ gchar *key;
+ GVariant *value;
+ MMFirmwareProperties *self;
+
+ if (!dictionary) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create Firmware properties from empty dictionary");
+ return NULL;
+ }
+
+ if (!g_variant_is_of_type (dictionary, G_VARIANT_TYPE ("a{sv}"))) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create Firmware properties from dictionary: "
+ "invalid variant type received");
+ return NULL;
+ }
+
+ self = firmware_properties_new_empty ();
+
+ g_variant_iter_init (&iter, dictionary);
+ while (!inner_error &&
+ g_variant_iter_next (&iter, "{sv}", &key, &value)) {
+ consume_variant (self,
+ key,
+ value,
+ &inner_error);
+ g_free (key);
+ g_variant_unref (value);
+ }
+
+ /* If error, destroy the object */
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ g_object_unref (self);
+ return NULL;
+ }
+
+ /* If mandatory properties missing, destroy the object */
+ if (!self->priv->name ||
+ !self->priv->version ||
+ self->priv->image_type == MM_FIRMWARE_IMAGE_TYPE_UNKNOWN) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create Firmware properties from dictionary: "
+ "mandatory parameter missing");
+ g_object_unref (self);
+ return NULL;
+ }
+
+ return self;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_firmware_properties_new:
+ * @image_type: A #MMFirmwareImageType specifying the type of the image.
+ * @name: The unique name of the image.
+ * @version: The version of the image.
+ *
+ * Creates a new #MMFirmwareProperties object with the properties specified.
+ *
+ * Returns: (transfer full): A #MMFirmwareProperties or %NULL if @error is set. The returned value should be freed with g_object_unref().
+ */
+MMFirmwareProperties *
+mm_firmware_properties_new (MMFirmwareImageType image_type,
+ const gchar *name,
+ const gchar *version)
+{
+ MMFirmwareProperties *self;
+
+ g_return_val_if_fail (image_type != MM_FIRMWARE_IMAGE_TYPE_UNKNOWN, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (version != NULL, NULL);
+
+ self = firmware_properties_new_empty ();
+ self->priv->image_type = image_type;
+ self->priv->name = g_strdup (name);
+ self->priv->version = g_strdup (version);
+
+ return self;
+}
+
+static MMFirmwareProperties *
+firmware_properties_new_empty (void)
+{
+ return (MM_FIRMWARE_PROPERTIES (
+ g_object_new (MM_TYPE_FIRMWARE_PROPERTIES, NULL)));
+}
+
+static void
+mm_firmware_properties_init (MMFirmwareProperties *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ MM_TYPE_FIRMWARE_PROPERTIES,
+ MMFirmwarePropertiesPrivate);
+
+ /* Some defaults */
+ self->priv->image_type = MM_FIRMWARE_IMAGE_TYPE_UNKNOWN;
+}
+
+static void
+finalize (GObject *object)
+{
+ MMFirmwareProperties *self = MM_FIRMWARE_PROPERTIES (object);
+
+ g_free (self->priv->name);
+ g_free (self->priv->version);
+
+ G_OBJECT_CLASS (mm_firmware_properties_parent_class)->finalize (object);
+}
+
+static void
+mm_firmware_properties_class_init (MMFirmwarePropertiesClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMFirmwarePropertiesPrivate));
+
+ object_class->finalize = finalize;
+}
diff --git a/libmm-glib/mm-firmware-properties.h b/libmm-glib/mm-firmware-properties.h
new file mode 100644
index 00000000..83973443
--- /dev/null
+++ b/libmm-glib/mm-firmware-properties.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Google Inc.
+ */
+
+#ifndef MM_FIRMWARE_PROPERTIES_H
+#define MM_FIRMWARE_PROPERTIES_H
+
+#include <ModemManager.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MM_TYPE_FIRMWARE_PROPERTIES (mm_firmware_properties_get_type ())
+#define MM_FIRMWARE_PROPERTIES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_FIRMWARE_PROPERTIES, MMFirmwareProperties))
+#define MM_FIRMWARE_PROPERTIES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_FIRMWARE_PROPERTIES, MMFirmwarePropertiesClass))
+#define MM_IS_FIRMWARE_PROPERTIES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_FIRMWARE_PROPERTIES))
+#define MM_IS_FIRMWARE_PROPERTIES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_FIRMWARE_PROPERTIES))
+#define MM_FIRMWARE_PROPERTIES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_FIRMWARE_PROPERTIES, MMFirmwarePropertiesClass))
+
+typedef struct _MMFirmwareProperties MMFirmwareProperties;
+typedef struct _MMFirmwarePropertiesClass MMFirmwarePropertiesClass;
+typedef struct _MMFirmwarePropertiesPrivate MMFirmwarePropertiesPrivate;
+
+/**
+ * MMFirmwareProperties:
+ *
+ * The #MMFirmwareProperties structure contains private data and should only be accessed
+ * using the provided API.
+ */
+struct _MMFirmwareProperties {
+ /*< private >*/
+ GObject parent;
+ MMFirmwarePropertiesPrivate *priv;
+};
+
+struct _MMFirmwarePropertiesClass {
+ /*< private >*/
+ GObjectClass parent;
+};
+
+GType mm_firmware_properties_get_type (void);
+
+MMFirmwareProperties *mm_firmware_properties_new (MMFirmwareImageType image_type,
+ const gchar *name,
+ const gchar *version);
+MMFirmwareProperties *mm_firmware_properties_new_from_dictionary (GVariant *dictionary,
+ GError **error);
+
+const gchar *mm_firmware_properties_get_name (MMFirmwareProperties *properties);
+const gchar *mm_firmware_properties_get_version (MMFirmwareProperties *properties);
+MMFirmwareImageType mm_firmware_properties_get_image_type (MMFirmwareProperties *properties);
+
+GVariant *mm_firmware_properties_get_dictionary (MMFirmwareProperties *self);
+
+G_END_DECLS
+
+#endif /* MM_FIRMWARE_PROPERTIES_H */
diff --git a/libmm-glib/mm-location-3gpp.c b/libmm-glib/mm-location-3gpp.c
new file mode 100644
index 00000000..8ac599f4
--- /dev/null
+++ b/libmm-glib/mm-location-3gpp.c
@@ -0,0 +1,280 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Google, Inc.
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "mm-errors-types.h"
+#include "mm-common-helpers.h"
+#include "mm-location-3gpp.h"
+
+G_DEFINE_TYPE (MMLocation3gpp, mm_location_3gpp, G_TYPE_OBJECT);
+
+struct _MMLocation3gppPrivate {
+ guint mobile_country_code;
+ guint mobile_network_code;
+ gulong location_area_code;
+ gulong cell_id;
+};
+
+/*****************************************************************************/
+
+guint
+mm_location_3gpp_get_mobile_country_code (MMLocation3gpp *self)
+{
+ g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), 0);
+
+ return self->priv->mobile_country_code;
+}
+
+guint
+mm_location_3gpp_get_mobile_network_code (MMLocation3gpp *self)
+{
+ g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), 0);
+
+ return self->priv->mobile_network_code;
+}
+
+gulong
+mm_location_3gpp_get_location_area_code (MMLocation3gpp *self)
+{
+ g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), 0);
+
+ return self->priv->location_area_code;
+}
+
+gulong
+mm_location_3gpp_get_cell_id (MMLocation3gpp *self)
+{
+ g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), 0);
+
+ return self->priv->cell_id;
+}
+
+gboolean
+mm_location_3gpp_set_mobile_country_code (MMLocation3gpp *self,
+ guint mobile_country_code)
+{
+ g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), FALSE);
+
+ /* If no change in the location info, don't do anything */
+ if (self->priv->mobile_country_code == mobile_country_code)
+ return FALSE;
+
+ self->priv->mobile_country_code = mobile_country_code;
+ return TRUE;
+}
+
+gboolean
+mm_location_3gpp_set_mobile_network_code (MMLocation3gpp *self,
+ guint mobile_network_code)
+{
+ g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), FALSE);
+
+ /* If no change in the location info, don't do anything */
+ if (self->priv->mobile_network_code == mobile_network_code)
+ return FALSE;
+
+ self->priv->mobile_network_code = mobile_network_code;
+ return TRUE;
+}
+
+gboolean
+mm_location_3gpp_set_location_area_code (MMLocation3gpp *self,
+ gulong location_area_code)
+{
+ g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), FALSE);
+
+ /* If no change in the location info, don't do anything */
+ if (self->priv->location_area_code == location_area_code)
+ return FALSE;
+
+ self->priv->location_area_code = location_area_code;
+ return TRUE;
+}
+
+
+gboolean
+mm_location_3gpp_set_cell_id (MMLocation3gpp *self,
+ gulong cell_id)
+{
+ g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), FALSE);
+
+ /* If no change in the location info, don't do anything */
+ if (self->priv->cell_id == cell_id)
+ return FALSE;
+
+ self->priv->cell_id = cell_id;
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+GVariant *
+mm_location_3gpp_get_string_variant (MMLocation3gpp *self)
+{
+ GVariant *variant = NULL;
+
+ g_return_val_if_fail (MM_IS_LOCATION_3GPP (self), NULL);
+
+ if (self->priv->mobile_country_code &&
+ self->priv->mobile_network_code &&
+ self->priv->location_area_code &&
+ self->priv->cell_id) {
+ gchar *str;
+
+ str = g_strdup_printf ("%u,%u,%lX,%lX",
+ self->priv->mobile_country_code,
+ self->priv->mobile_network_code,
+ self->priv->location_area_code,
+ self->priv->cell_id);
+
+ variant = g_variant_new_string (str);
+ g_free (str);
+ }
+
+ return variant;
+}
+
+/*****************************************************************************/
+
+static gboolean
+validate_string_length (const gchar *display,
+ const gchar *str,
+ guint max_length,
+ GError **error)
+{
+ /* Avoid empty strings */
+ if (!str || !str[0]) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid %s: none given",
+ display);
+ return FALSE;
+ }
+
+ /* Check max length of the field */
+ if (strlen (str) > max_length) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid %s: longer than the maximum expected (%u): '%s'",
+ display,
+ max_length,
+ str);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+validate_numeric_string_content (const gchar *display,
+ const gchar *str,
+ gboolean hex,
+ GError **error)
+{
+ guint i;
+
+ for (i = 0; str[i]; i++) {
+ if ((hex && !g_ascii_isxdigit (str[i])) ||
+ (!hex && !g_ascii_isdigit (str[i]))) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid %s: unexpected char (%c): '%s'",
+ display,
+ str[i],
+ str);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+MMLocation3gpp *
+mm_location_3gpp_new_from_string_variant (GVariant *string,
+ GError **error)
+{
+ MMLocation3gpp *self = NULL;
+ gchar **split;
+
+ if (!g_variant_is_of_type (string, G_VARIANT_TYPE_STRING)) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create 3GPP location from string: "
+ "invalid variant type received");
+ return NULL;
+ }
+
+ split = g_strsplit (g_variant_get_string (string, NULL), ",", -1);
+ if (!split) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid 3GPP location string: '%s'",
+ g_variant_get_string (string, NULL));
+ return NULL;
+ }
+
+ /* Validate fields */
+ if (validate_string_length ("MCC", split[0], 3, error) &&
+ validate_numeric_string_content ("MCC", split[0], FALSE, error) &&
+ validate_string_length ("MNC", split[1], 3, error) &&
+ validate_numeric_string_content ("MNC", split[1], FALSE, error) &&
+ validate_string_length ("Location area code", split[2], 4, error) &&
+ validate_numeric_string_content ("Location area code", split[2], TRUE, error) &&
+ validate_string_length ("Cell ID", split[3], 8, error) &&
+ validate_numeric_string_content ("Cell ID", split[3], TRUE, error)) {
+ /* Create new location object */
+ self = mm_location_3gpp_new ();
+ self->priv->mobile_country_code = strtol (split[0], NULL, 10);
+ self->priv->mobile_network_code = strtol (split[1], NULL, 10);
+ self->priv->location_area_code = strtol (split[2], NULL, 16);
+ self->priv->cell_id = strtol (split[3], NULL, 16);
+ }
+
+ g_strfreev (split);
+ return self;
+}
+
+/*****************************************************************************/
+
+MMLocation3gpp *
+mm_location_3gpp_new (void)
+{
+ return (MM_LOCATION_3GPP (
+ g_object_new (MM_TYPE_LOCATION_3GPP, NULL)));
+}
+
+static void
+mm_location_3gpp_init (MMLocation3gpp *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
+ MM_TYPE_LOCATION_3GPP,
+ MMLocation3gppPrivate);
+}
+
+static void
+mm_location_3gpp_class_init (MMLocation3gppClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMLocation3gppPrivate));
+}
diff --git a/libmm-glib/mm-location-3gpp.h b/libmm-glib/mm-location-3gpp.h
new file mode 100644
index 00000000..41469c85
--- /dev/null
+++ b/libmm-glib/mm-location-3gpp.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Google, Inc.
+ */
+
+#ifndef MM_LOCATION_3GPP_H
+#define MM_LOCATION_3GPP_H
+
+#include <ModemManager.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MM_TYPE_LOCATION_3GPP (mm_location_3gpp_get_type ())
+#define MM_LOCATION_3GPP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_LOCATION_3GPP, MMLocation3gpp))
+#define MM_LOCATION_3GPP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_LOCATION_3GPP, MMLocation3gppClass))
+#define MM_IS_LOCATION_3GPP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_LOCATION_3GPP))
+#define MM_IS_LOCATION_3GPP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_LOCATION_3GPP))
+#define MM_LOCATION_3GPP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_LOCATION_3GPP, MMLocation3gppClass))
+
+typedef struct _MMLocation3gpp MMLocation3gpp;
+typedef struct _MMLocation3gppClass MMLocation3gppClass;
+typedef struct _MMLocation3gppPrivate MMLocation3gppPrivate;
+
+struct _MMLocation3gpp {
+ GObject parent;
+ MMLocation3gppPrivate *priv;
+};
+
+struct _MMLocation3gppClass {
+ GObjectClass parent;
+};
+
+GType mm_location_3gpp_get_type (void);
+
+MMLocation3gpp *mm_location_3gpp_new (void);
+MMLocation3gpp *mm_location_3gpp_new_from_string_variant (GVariant *string,
+ GError **error);
+
+gboolean mm_location_3gpp_set_mobile_country_code (MMLocation3gpp *self,
+ guint mobile_country_code);
+gboolean mm_location_3gpp_set_mobile_network_code (MMLocation3gpp *self,
+ guint mobile_network_code);
+gboolean mm_location_3gpp_set_location_area_code (MMLocation3gpp *self,
+ gulong location_area_code);
+gboolean mm_location_3gpp_set_cell_id (MMLocation3gpp *self,
+ gulong cell_id);
+
+guint mm_location_3gpp_get_mobile_country_code (MMLocation3gpp *self);
+guint mm_location_3gpp_get_mobile_network_code (MMLocation3gpp *self);
+gulong mm_location_3gpp_get_location_area_code (MMLocation3gpp *self);
+gulong mm_location_3gpp_get_cell_id (MMLocation3gpp *self);
+
+GVariant *mm_location_3gpp_get_string_variant (MMLocation3gpp *self);
+
+G_END_DECLS
+
+#endif /* MM_LOCATION_3GPP_H */
diff --git a/libmm-glib/mm-location-gps-nmea.c b/libmm-glib/mm-location-gps-nmea.c
new file mode 100644
index 00000000..de6478dc
--- /dev/null
+++ b/libmm-glib/mm-location-gps-nmea.c
@@ -0,0 +1,248 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Lanedo GmbH <aleksander@lanedo.com>
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "mm-common-helpers.h"
+#include "mm-errors-types.h"
+#include "mm-location-gps-nmea.h"
+
+G_DEFINE_TYPE (MMLocationGpsNmea, mm_location_gps_nmea, G_TYPE_OBJECT);
+
+struct _MMLocationGpsNmeaPrivate {
+ GHashTable *traces;
+ GRegex *sequence_regex;
+};
+
+/*****************************************************************************/
+
+static gboolean
+check_append_or_replace (MMLocationGpsNmea *self,
+ const gchar *trace)
+{
+ /* By default, replace */
+ gboolean append_or_replace = FALSE;
+ GMatchInfo *match_info = NULL;
+
+ if (G_UNLIKELY (!self->priv->sequence_regex))
+ self->priv->sequence_regex = g_regex_new ("\\$GPGSV,(\\d),(\\d).*",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE,
+ 0,
+ NULL);
+
+ if (g_regex_match (self->priv->sequence_regex, trace, 0, &match_info)) {
+ guint index;
+
+ /* If we don't have the first element of a sequence, append */
+ if (mm_get_uint_from_match_info (match_info, 2, &index) && index != 1)
+ append_or_replace = TRUE;
+ }
+ g_match_info_free (match_info);
+
+ return append_or_replace;
+}
+
+static gboolean
+location_gps_nmea_take_trace (MMLocationGpsNmea *self,
+ gchar *trace)
+{
+ gchar *i;
+ gchar *trace_type;
+
+ i = strchr (trace, ',');
+ if (!i || i == trace)
+ return FALSE;
+
+ trace_type = g_malloc (i - trace + 1);
+ memcpy (trace_type, trace, i - trace);
+ trace_type[i - trace] = '\0';
+
+ /* Some traces are part of a SEQUENCE; so we need to decide whether we
+ * completely replace the previous trace, or we append the new one to
+ * the already existing list */
+ if (check_append_or_replace (self, trace)) {
+ /* Append */
+ const gchar *previous;
+
+ previous = g_hash_table_lookup (self->priv->traces, trace_type);
+ if (previous) {
+ gchar *sequence;
+
+ /* Skip the trace if we already have it there */
+ if (strstr (previous, trace))
+ return TRUE;
+
+ sequence = g_strdup_printf ("%s%s%s",
+ previous,
+ g_str_has_suffix (previous, "\r\n") ? "" : "\r\n",
+ trace);
+ g_free (trace);
+ trace = sequence;
+ }
+ }
+
+ g_hash_table_replace (self->priv->traces,
+ trace_type,
+ trace);
+ return TRUE;
+}
+
+gboolean
+mm_location_gps_nmea_add_trace (MMLocationGpsNmea *self,
+ const gchar *trace)
+{
+ return location_gps_nmea_take_trace (self, g_strdup (trace));
+}
+
+/*****************************************************************************/
+
+const gchar *
+mm_location_gps_nmea_get_trace (MMLocationGpsNmea *self,
+ const gchar *trace_type)
+{
+ return (const gchar *)g_hash_table_lookup (self->priv->traces, trace_type);
+}
+
+/*****************************************************************************/
+
+static void
+build_full_foreach (const gchar *trace_type,
+ const gchar *trace,
+ GString **built)
+{
+ if ((*built)->len == 0 || g_str_has_suffix ((*built)->str, "\r\n"))
+ g_string_append (*built, trace);
+ else
+ g_string_append_printf (*built, "\r\n%s", trace);
+}
+
+gchar *
+mm_location_gps_nmea_build_full (MMLocationGpsNmea *self)
+{
+ GString *built;
+
+ built = g_string_new ("");
+ g_hash_table_foreach (self->priv->traces,
+ (GHFunc)build_full_foreach,
+ &built);
+ return g_string_free (built, FALSE);
+}
+
+/*****************************************************************************/
+
+GVariant *
+mm_location_gps_nmea_get_string_variant (MMLocationGpsNmea *self)
+{
+ GVariant *variant = NULL;
+ gchar *built;
+
+ g_return_val_if_fail (MM_IS_LOCATION_GPS_NMEA (self), NULL);
+
+ built = mm_location_gps_nmea_build_full (self);
+ variant = g_variant_new_string (built);
+ g_free (built);
+
+ return variant;
+}
+
+/*****************************************************************************/
+
+MMLocationGpsNmea *
+mm_location_gps_nmea_new_from_string_variant (GVariant *string,
+ GError **error)
+{
+ MMLocationGpsNmea *self = NULL;
+ gchar **split;
+ guint i;
+
+ if (!g_variant_is_of_type (string, G_VARIANT_TYPE_STRING)) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create GPS NMEA location from string: "
+ "invalid variant type received");
+ return NULL;
+ }
+
+ split = g_strsplit (g_variant_get_string (string, NULL), "\r\n", -1);
+ if (!split) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid GPS NMEA location string: '%s'",
+ g_variant_get_string (string, NULL));
+ return NULL;
+ }
+
+ /* Create new location object */
+ self = mm_location_gps_nmea_new ();
+
+ for (i = 0; split[i]; i++) {
+ if (!location_gps_nmea_take_trace (self, split[i]))
+ g_free (split[i]);
+ }
+
+ /* Note that the strings in the array of strings were already taken
+ * or freed */
+ g_free (split);
+
+ return self;
+}
+
+/*****************************************************************************/
+
+MMLocationGpsNmea *
+mm_location_gps_nmea_new (void)
+{
+ return (MM_LOCATION_GPS_NMEA (
+ g_object_new (MM_TYPE_LOCATION_GPS_NMEA, NULL)));
+}
+
+static void
+mm_location_gps_nmea_init (MMLocationGpsNmea *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
+ MM_TYPE_LOCATION_GPS_NMEA,
+ MMLocationGpsNmeaPrivate);
+
+ self->priv->traces = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_free);
+}
+
+static void
+finalize (GObject *object)
+{
+ MMLocationGpsNmea *self = MM_LOCATION_GPS_NMEA (object);
+
+ g_hash_table_destroy (self->priv->traces);
+ if (self->priv->sequence_regex)
+ g_regex_unref (self->priv->sequence_regex);
+
+ G_OBJECT_CLASS (mm_location_gps_nmea_parent_class)->finalize (object);
+}
+
+static void
+mm_location_gps_nmea_class_init (MMLocationGpsNmeaClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMLocationGpsNmeaPrivate));
+
+ object_class->finalize = finalize;
+}
diff --git a/libmm-glib/mm-location-gps-nmea.h b/libmm-glib/mm-location-gps-nmea.h
new file mode 100644
index 00000000..c5ebe42c
--- /dev/null
+++ b/libmm-glib/mm-location-gps-nmea.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Lanedo GmbH <aleksander@lanedo.com>
+ */
+
+#ifndef MM_LOCATION_GPS_NMEA_H
+#define MM_LOCATION_GPS_NMEA_H
+
+#include <ModemManager.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MM_TYPE_LOCATION_GPS_NMEA (mm_location_gps_nmea_get_type ())
+#define MM_LOCATION_GPS_NMEA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_LOCATION_GPS_NMEA, MMLocationGpsNmea))
+#define MM_LOCATION_GPS_NMEA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_LOCATION_GPS_NMEA, MMLocationGpsNmeaClass))
+#define MM_IS_LOCATION_GPS_NMEA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_LOCATION_GPS_NMEA))
+#define MM_IS_LOCATION_GPS_NMEA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_LOCATION_GPS_NMEA))
+#define MM_LOCATION_GPS_NMEA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_LOCATION_GPS_NMEA, MMLocationGpsNmeaClass))
+
+typedef struct _MMLocationGpsNmea MMLocationGpsNmea;
+typedef struct _MMLocationGpsNmeaClass MMLocationGpsNmeaClass;
+typedef struct _MMLocationGpsNmeaPrivate MMLocationGpsNmeaPrivate;
+
+struct _MMLocationGpsNmea {
+ GObject parent;
+ MMLocationGpsNmeaPrivate *priv;
+};
+
+struct _MMLocationGpsNmeaClass {
+ GObjectClass parent;
+};
+
+GType mm_location_gps_nmea_get_type (void);
+
+MMLocationGpsNmea *mm_location_gps_nmea_new (void);
+MMLocationGpsNmea *mm_location_gps_nmea_new_from_string_variant (GVariant *string,
+ GError **error);
+
+gboolean mm_location_gps_nmea_add_trace (MMLocationGpsNmea *self,
+ const gchar *trace);
+
+const gchar *mm_location_gps_nmea_get_trace (MMLocationGpsNmea *self,
+ const gchar *trace_type);
+gchar *mm_location_gps_nmea_build_full (MMLocationGpsNmea *self);
+
+GVariant *mm_location_gps_nmea_get_string_variant (MMLocationGpsNmea *self);
+
+G_END_DECLS
+
+#endif /* MM_LOCATION_GPS_NMEA_H */
diff --git a/libmm-glib/mm-location-gps-raw.c b/libmm-glib/mm-location-gps-raw.c
new file mode 100644
index 00000000..47eae14b
--- /dev/null
+++ b/libmm-glib/mm-location-gps-raw.c
@@ -0,0 +1,337 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Lanedo GmbH <aleksander@lanedo.com>
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "mm-common-helpers.h"
+#include "mm-errors-types.h"
+#include "mm-location-gps-raw.h"
+
+G_DEFINE_TYPE (MMLocationGpsRaw, mm_location_gps_raw, G_TYPE_OBJECT);
+
+#define PROPERTY_UTC_TIME "utc-time"
+#define PROPERTY_LATITUDE "latitude"
+#define PROPERTY_LONGITUDE "longitude"
+#define PROPERTY_ALTITUDE "altitude"
+
+struct _MMLocationGpsRawPrivate {
+ GRegex *gpgga_regex;
+
+ gchar *utc_time;
+ gdouble latitude;
+ gdouble longitude;
+ gdouble altitude;
+};
+
+/*****************************************************************************/
+
+const gchar *
+mm_location_gps_raw_get_utc_time (MMLocationGpsRaw *self)
+{
+ g_return_val_if_fail (MM_IS_LOCATION_GPS_RAW (self), NULL);
+
+ return self->priv->utc_time;
+}
+
+gdouble
+mm_location_gps_raw_get_longitude (MMLocationGpsRaw *self)
+{
+ g_return_val_if_fail (MM_IS_LOCATION_GPS_RAW (self),
+ MM_LOCATION_GPS_RAW_LONGITUDE_UNKNOWN);
+
+ return self->priv->longitude;
+}
+
+gdouble
+mm_location_gps_raw_get_latitude (MMLocationGpsRaw *self)
+{
+ g_return_val_if_fail (MM_IS_LOCATION_GPS_RAW (self),
+ MM_LOCATION_GPS_RAW_LATITUDE_UNKNOWN);
+
+ return self->priv->latitude;
+}
+
+gdouble
+mm_location_gps_raw_get_altitude (MMLocationGpsRaw *self)
+{
+ g_return_val_if_fail (MM_IS_LOCATION_GPS_RAW (self),
+ MM_LOCATION_GPS_RAW_ALTITUDE_UNKNOWN);
+
+ return self->priv->altitude;
+}
+
+/*****************************************************************************/
+
+static gboolean
+get_longitude_or_latitude_from_match_info (GMatchInfo *match_info,
+ guint32 match_index,
+ gdouble *out)
+{
+ gchar *aux;
+ gchar *s;
+ gboolean ret = FALSE;
+ gdouble minutes;
+ gdouble degrees;
+
+ s = g_match_info_fetch (match_info, match_index);
+ if (!s)
+ goto out;
+
+ /* 4533.35 is 45 degrees and 33.35 minutes */
+
+ aux = strchr (s, '.');
+ if (!aux || ((aux - s) < 3))
+ goto out;
+
+ aux -= 2;
+ if (!mm_get_double_from_str (aux, &minutes))
+ goto out;
+
+ aux[0] = '\0';
+ if (!mm_get_double_from_str (s, &degrees))
+ goto out;
+
+ /* Include the minutes as part of the degrees */
+ *out = degrees + (minutes / 60.0);
+ ret = TRUE;
+
+out:
+ g_free (s);
+
+ return ret;
+}
+
+gboolean
+mm_location_gps_raw_add_trace (MMLocationGpsRaw *self,
+ const gchar *trace)
+{
+ GMatchInfo *match_info = NULL;
+
+ /* Current implementation works only with $GPGGA traces */
+ if (!g_str_has_prefix (trace, "$GPGGA"))
+ return FALSE;
+
+ /*
+ * $GPGGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh
+ * 1 = UTC of Position
+ * 2 = Latitude
+ * 3 = N or S
+ * 4 = Longitude
+ * 5 = E or W
+ * 6 = GPS quality indicator (0=invalid; 1=GPS fix; 2=Diff. GPS fix)
+ * 7 = Number of satellites in use [not those in view]
+ * 8 = Horizontal dilution of position
+ * 9 = Antenna altitude above/below mean sea level (geoid)
+ * 10 = Meters (Antenna height unit)
+ * 11 = Geoidal separation (Diff. between WGS-84 earth ellipsoid and
+ * mean sea level. -=geoid is below WGS-84 ellipsoid)
+ * 12 = Meters (Units of geoidal separation)
+ * 13 = Age in seconds since last update from diff. reference station
+ * 14 = Diff. reference station ID#
+ * 15 = Checksum
+ */
+ if (G_UNLIKELY (!self->priv->gpgga_regex))
+ self->priv->gpgga_regex = g_regex_new ("\\$GPGGA,(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*),(.*)\\*(.*).*",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE,
+ 0,
+ NULL);
+
+ if (g_regex_match (self->priv->gpgga_regex, trace, 0, &match_info)) {
+ /* UTC time */
+ if (self->priv->utc_time)
+ g_free (self->priv->utc_time);
+ self->priv->utc_time = g_match_info_fetch (match_info, 1);
+
+ /* Latitude */
+ self->priv->latitude = MM_LOCATION_GPS_RAW_LATITUDE_UNKNOWN;
+ if (get_longitude_or_latitude_from_match_info (match_info, 2, &self->priv->latitude)) {
+ gchar *str;
+
+ /* N/S */
+ str = g_match_info_fetch (match_info, 3);
+ if (str && str[0] == 'S')
+ self->priv->latitude *= -1;
+ g_free (str);
+ }
+
+ /* Longitude */
+ self->priv->longitude = MM_LOCATION_GPS_RAW_LONGITUDE_UNKNOWN;
+ if (get_longitude_or_latitude_from_match_info (match_info, 4, &self->priv->longitude)) {
+ gchar *str;
+
+ /* N/S */
+ str = g_match_info_fetch (match_info, 5);
+ if (str && str[0] == 'W')
+ self->priv->longitude *= -1;
+ g_free (str);
+ }
+
+ /* Altitude */
+ self->priv->altitude = MM_LOCATION_GPS_RAW_ALTITUDE_UNKNOWN;
+ mm_get_double_from_match_info (match_info, 9, &self->priv->altitude);
+ }
+
+ g_match_info_free (match_info);
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+GVariant *
+mm_location_gps_raw_get_dictionary (MMLocationGpsRaw *self)
+{
+ GVariantBuilder builder;
+
+ /* We do allow NULL */
+ if (!self)
+ return NULL;
+
+ g_return_val_if_fail (MM_IS_LOCATION_GPS_RAW (self), NULL);
+
+ /* If mandatory parameters are not found, return NULL */
+ if (!self->priv->utc_time ||
+ self->priv->longitude == MM_LOCATION_GPS_RAW_LONGITUDE_UNKNOWN ||
+ self->priv->latitude == MM_LOCATION_GPS_RAW_LATITUDE_UNKNOWN)
+ return NULL;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_UTC_TIME,
+ g_variant_new_string (self->priv->utc_time));
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_LONGITUDE,
+ g_variant_new_double (self->priv->longitude));
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_LATITUDE,
+ g_variant_new_double (self->priv->latitude));
+
+ /* Altitude is optional */
+ if (self->priv->altitude != MM_LOCATION_GPS_RAW_ALTITUDE_UNKNOWN)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_ALTITUDE,
+ g_variant_new_double (self->priv->altitude));
+
+ return g_variant_ref_sink (g_variant_builder_end (&builder));
+}
+
+/*****************************************************************************/
+
+MMLocationGpsRaw *
+mm_location_gps_raw_new_from_dictionary (GVariant *dictionary,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ MMLocationGpsRaw *self;
+ GVariantIter iter;
+ gchar *key;
+ GVariant *value;
+
+ self = mm_location_gps_raw_new ();
+ if (!dictionary)
+ return self;
+
+ if (!g_variant_is_of_type (dictionary, G_VARIANT_TYPE ("a{sv}"))) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create GPS RAW location from dictionary: "
+ "invalid variant type received");
+ g_object_unref (self);
+ return NULL;
+ }
+
+ g_variant_iter_init (&iter, dictionary);
+ while (!inner_error &&
+ g_variant_iter_next (&iter, "{sv}", &key, &value)) {
+ if (g_str_equal (key, PROPERTY_UTC_TIME))
+ self->priv->utc_time = g_variant_dup_string (value, NULL);
+ else if (g_str_equal (key, PROPERTY_LONGITUDE))
+ self->priv->longitude = g_variant_get_double (value);
+ else if (g_str_equal (key, PROPERTY_LATITUDE))
+ self->priv->latitude = g_variant_get_double (value);
+ else if (g_str_equal (key, PROPERTY_ALTITUDE))
+ self->priv->altitude = g_variant_get_double (value);
+ g_free (key);
+ g_variant_unref (value);
+ }
+
+ /* If any of the mandatory parameters is missing, cleanup */
+ if (!self->priv->utc_time ||
+ self->priv->longitude == MM_LOCATION_GPS_RAW_LONGITUDE_UNKNOWN ||
+ self->priv->latitude == MM_LOCATION_GPS_RAW_LATITUDE_UNKNOWN) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create GPS RAW location from dictionary: "
+ "mandatory parameters missing "
+ "(utc-time: %s, longitude: %s, latitude: %s)",
+ self->priv->utc_time ? "yes" : "missing",
+ (self->priv->longitude != MM_LOCATION_GPS_RAW_LONGITUDE_UNKNOWN) ? "yes" : "missing",
+ (self->priv->latitude != MM_LOCATION_GPS_RAW_LATITUDE_UNKNOWN) ? "yes" : "missing");
+ g_clear_object (&self);
+ }
+
+ return self;
+}
+
+/*****************************************************************************/
+
+MMLocationGpsRaw *
+mm_location_gps_raw_new (void)
+{
+ return (MM_LOCATION_GPS_RAW (
+ g_object_new (MM_TYPE_LOCATION_GPS_RAW, NULL)));
+}
+
+static void
+mm_location_gps_raw_init (MMLocationGpsRaw *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
+ MM_TYPE_LOCATION_GPS_RAW,
+ MMLocationGpsRawPrivate);
+
+ self->priv->utc_time = NULL;
+ self->priv->latitude = MM_LOCATION_GPS_RAW_LATITUDE_UNKNOWN;
+ self->priv->longitude = MM_LOCATION_GPS_RAW_LONGITUDE_UNKNOWN;
+ self->priv->altitude = MM_LOCATION_GPS_RAW_ALTITUDE_UNKNOWN;
+}
+
+static void
+finalize (GObject *object)
+{
+ MMLocationGpsRaw *self = MM_LOCATION_GPS_RAW (object);
+
+ if (self->priv->gpgga_regex)
+ g_regex_unref (self->priv->gpgga_regex);
+
+ G_OBJECT_CLASS (mm_location_gps_raw_parent_class)->finalize (object);
+}
+
+static void
+mm_location_gps_raw_class_init (MMLocationGpsRawClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMLocationGpsRawPrivate));
+
+ object_class->finalize = finalize;
+}
diff --git a/libmm-glib/mm-location-gps-raw.h b/libmm-glib/mm-location-gps-raw.h
new file mode 100644
index 00000000..46f36580
--- /dev/null
+++ b/libmm-glib/mm-location-gps-raw.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Lanedo GmbH <aleksander@lanedo.com>
+ */
+
+#ifndef MM_LOCATION_GPS_RAW_H
+#define MM_LOCATION_GPS_RAW_H
+
+#include <ModemManager.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MM_TYPE_LOCATION_GPS_RAW (mm_location_gps_raw_get_type ())
+#define MM_LOCATION_GPS_RAW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_LOCATION_GPS_RAW, MMLocationGpsRaw))
+#define MM_LOCATION_GPS_RAW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_LOCATION_GPS_RAW, MMLocationGpsRawClass))
+#define MM_IS_LOCATION_GPS_RAW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_LOCATION_GPS_RAW))
+#define MM_IS_LOCATION_GPS_RAW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_LOCATION_GPS_RAW))
+#define MM_LOCATION_GPS_RAW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_LOCATION_GPS_RAW, MMLocationGpsRawClass))
+
+
+/* Proper longitude values will fall in the [-180,180] range
+ * Proper latitude values will fall in the [-90,90] range
+ */
+#define MM_LOCATION_GPS_RAW_LONGITUDE_UNKNOWN G_MINDOUBLE
+#define MM_LOCATION_GPS_RAW_LATITUDE_UNKNOWN G_MINDOUBLE
+#define MM_LOCATION_GPS_RAW_ALTITUDE_UNKNOWN G_MINDOUBLE
+
+typedef struct _MMLocationGpsRaw MMLocationGpsRaw;
+typedef struct _MMLocationGpsRawClass MMLocationGpsRawClass;
+typedef struct _MMLocationGpsRawPrivate MMLocationGpsRawPrivate;
+
+struct _MMLocationGpsRaw {
+ GObject parent;
+ MMLocationGpsRawPrivate *priv;
+};
+
+struct _MMLocationGpsRawClass {
+ GObjectClass parent;
+};
+
+GType mm_location_gps_raw_get_type (void);
+
+MMLocationGpsRaw *mm_location_gps_raw_new (void);
+MMLocationGpsRaw *mm_location_gps_raw_new_from_dictionary (GVariant *string,
+ GError **error);
+
+const gchar *mm_location_gps_raw_get_utc_time (MMLocationGpsRaw *self);
+gdouble mm_location_gps_raw_get_longitude (MMLocationGpsRaw *self);
+gdouble mm_location_gps_raw_get_latitude (MMLocationGpsRaw *self);
+gdouble mm_location_gps_raw_get_altitude (MMLocationGpsRaw *self);
+
+gboolean mm_location_gps_raw_add_trace (MMLocationGpsRaw *self,
+ const gchar *trace);
+
+GVariant *mm_location_gps_raw_get_dictionary (MMLocationGpsRaw *self);
+
+G_END_DECLS
+
+#endif /* MM_LOCATION_GPS_RAW_H */
diff --git a/libmm-glib/mm-network-timezone.c b/libmm-glib/mm-network-timezone.c
new file mode 100644
index 00000000..dfb6914e
--- /dev/null
+++ b/libmm-glib/mm-network-timezone.c
@@ -0,0 +1,216 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Google, Inc.
+ */
+
+#include <string.h>
+
+#include "mm-errors-types.h"
+#include "mm-network-timezone.h"
+
+G_DEFINE_TYPE (MMNetworkTimezone, mm_network_timezone, G_TYPE_OBJECT);
+
+struct _MMNetworkTimezonePrivate {
+ gint32 offset;
+ gint32 dst_offset;
+ gint32 leap_seconds;
+};
+
+/*****************************************************************************/
+
+gint
+mm_network_timezone_get_offset (MMNetworkTimezone *self)
+{
+ g_return_val_if_fail (MM_IS_NETWORK_TIMEZONE (self),
+ MM_NETWORK_TIMEZONE_OFFSET_UNKNOWN);
+
+ return self->priv->offset;
+}
+
+gint
+mm_network_timezone_get_dst_offset (MMNetworkTimezone *self)
+{
+ g_return_val_if_fail (MM_IS_NETWORK_TIMEZONE (self),
+ MM_NETWORK_TIMEZONE_OFFSET_UNKNOWN);
+
+ return self->priv->dst_offset;
+}
+
+gint
+mm_network_timezone_get_leap_seconds (MMNetworkTimezone *self)
+{
+ g_return_val_if_fail (MM_IS_NETWORK_TIMEZONE (self),
+ MM_NETWORK_TIMEZONE_LEAP_SECONDS_UNKNOWN);
+
+ return self->priv->leap_seconds;
+}
+
+/*****************************************************************************/
+
+void
+mm_network_timezone_set_offset (MMNetworkTimezone *self,
+ gint offset)
+{
+ g_return_if_fail (MM_IS_NETWORK_TIMEZONE (self));
+
+ self->priv->offset = offset;
+}
+
+void
+mm_network_timezone_set_dst_offset (MMNetworkTimezone *self,
+ gint dst_offset)
+{
+ g_return_if_fail (MM_IS_NETWORK_TIMEZONE (self));
+
+ self->priv->dst_offset = dst_offset;
+}
+
+void
+mm_network_timezone_set_leap_seconds (MMNetworkTimezone *self,
+ gint leap_seconds)
+{
+ g_return_if_fail (MM_IS_NETWORK_TIMEZONE (self));
+
+ self->priv->leap_seconds = leap_seconds;
+}
+
+/*****************************************************************************/
+
+GVariant *
+mm_network_timezone_get_dictionary (MMNetworkTimezone *self)
+{
+ GVariantBuilder builder;
+
+ /* Allow NULL */
+ if (!self)
+ return NULL;
+
+ g_return_val_if_fail (MM_IS_NETWORK_TIMEZONE (self), NULL);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+ if (self->priv->offset != MM_NETWORK_TIMEZONE_OFFSET_UNKNOWN)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ "offset",
+ g_variant_new_int32 (self->priv->offset));
+
+ if (self->priv->dst_offset != MM_NETWORK_TIMEZONE_OFFSET_UNKNOWN)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ "dst-offset",
+ g_variant_new_int32 (self->priv->dst_offset));
+
+ if (self->priv->leap_seconds != MM_NETWORK_TIMEZONE_LEAP_SECONDS_UNKNOWN)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ "leap-seconds",
+ g_variant_new_int32 (self->priv->leap_seconds));
+
+ return g_variant_ref_sink (g_variant_builder_end (&builder));
+}
+
+/*****************************************************************************/
+
+MMNetworkTimezone *
+mm_network_timezone_new_from_dictionary (GVariant *dictionary,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ GVariantIter iter;
+ gchar *key;
+ GVariant *value;
+ MMNetworkTimezone *self;
+
+ self = mm_network_timezone_new ();
+ if (!dictionary)
+ return self;
+
+ if (!g_variant_is_of_type (dictionary, G_VARIANT_TYPE ("a{sv}"))) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create Network Timezone from dictionary: "
+ "invalid variant type received");
+ g_object_unref (self);
+ return NULL;
+ }
+
+ g_variant_iter_init (&iter, dictionary);
+ while (!inner_error &&
+ g_variant_iter_next (&iter, "{sv}", &key, &value)) {
+ /* All currently supported properties are signed integers,
+ * so we just check the value type here */
+ if (!g_variant_is_of_type (value, G_VARIANT_TYPE_INT32)) {
+ /* Set inner error, will stop the loop */
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid status dictionary, unexpected value type '%s'",
+ g_variant_get_type_string (value));
+ } else if (g_str_equal (key, "offset"))
+ self->priv->offset = g_variant_get_int32 (value);
+ else if (g_str_equal (key, "dst-offset"))
+ self->priv->dst_offset = g_variant_get_int32 (value);
+ else if (g_str_equal (key, "leap-seconds"))
+ self->priv->leap_seconds = g_variant_get_int32 (value);
+ else {
+ /* Set inner error, will stop the loop */
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid status dictionary, unexpected key '%s'",
+ key);
+ }
+
+ g_free (key);
+ g_variant_unref (value);
+ }
+
+ /* If error, destroy the object */
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ g_object_unref (self);
+ return NULL;
+ }
+
+ return self;
+}
+
+/*****************************************************************************/
+
+MMNetworkTimezone *
+mm_network_timezone_new (void)
+{
+ return (MM_NETWORK_TIMEZONE (
+ g_object_new (MM_TYPE_NETWORK_TIMEZONE, NULL)));
+}
+
+static void
+mm_network_timezone_init (MMNetworkTimezone *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
+ MM_TYPE_NETWORK_TIMEZONE,
+ MMNetworkTimezonePrivate);
+
+ /* Some defaults */
+ self->priv->offset = MM_NETWORK_TIMEZONE_OFFSET_UNKNOWN;
+ self->priv->dst_offset = MM_NETWORK_TIMEZONE_OFFSET_UNKNOWN;
+ self->priv->leap_seconds = MM_NETWORK_TIMEZONE_LEAP_SECONDS_UNKNOWN;
+}
+
+static void
+mm_network_timezone_class_init (MMNetworkTimezoneClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMNetworkTimezonePrivate));
+}
diff --git a/libmm-glib/mm-network-timezone.h b/libmm-glib/mm-network-timezone.h
new file mode 100644
index 00000000..2c27fe00
--- /dev/null
+++ b/libmm-glib/mm-network-timezone.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Google, Inc.
+ */
+
+#ifndef MM_NETWORK_TIMEZONE_H
+#define MM_NETWORK_TIMEZONE_H
+
+#include <ModemManager.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MM_TYPE_NETWORK_TIMEZONE (mm_network_timezone_get_type ())
+#define MM_NETWORK_TIMEZONE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_NETWORK_TIMEZONE, MMNetworkTimezone))
+#define MM_NETWORK_TIMEZONE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_NETWORK_TIMEZONE, MMNetworkTimezoneClass))
+#define MM_IS_NETWORK_TIMEZONE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_NETWORK_TIMEZONE))
+#define MM_IS_NETWORK_TIMEZONE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_NETWORK_TIMEZONE))
+#define MM_NETWORK_TIMEZONE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_NETWORK_TIMEZONE, MMNetworkTimezoneClass))
+
+#define MM_NETWORK_TIMEZONE_OFFSET_UNKNOWN G_MAXINT32
+#define MM_NETWORK_TIMEZONE_LEAP_SECONDS_UNKNOWN G_MAXINT32
+
+typedef struct _MMNetworkTimezone MMNetworkTimezone;
+typedef struct _MMNetworkTimezoneClass MMNetworkTimezoneClass;
+typedef struct _MMNetworkTimezonePrivate MMNetworkTimezonePrivate;
+
+struct _MMNetworkTimezone {
+ GObject parent;
+ MMNetworkTimezonePrivate *priv;
+};
+
+struct _MMNetworkTimezoneClass {
+ GObjectClass parent;
+};
+
+GType mm_network_timezone_get_type (void);
+
+MMNetworkTimezone *mm_network_timezone_new (void);
+MMNetworkTimezone *mm_network_timezone_new_from_dictionary (GVariant *dictionary,
+ GError **error);
+
+gint32 mm_network_timezone_get_offset (MMNetworkTimezone *self);
+gint32 mm_network_timezone_get_dst_offset (MMNetworkTimezone *self);
+gint32 mm_network_timezone_get_leap_seconds (MMNetworkTimezone *self);
+
+void mm_network_timezone_set_offset (MMNetworkTimezone *self,
+ gint offset);
+void mm_network_timezone_set_dst_offset (MMNetworkTimezone *self,
+ gint dst_offset);
+void mm_network_timezone_set_leap_seconds (MMNetworkTimezone *self,
+ gint leap_seconds);
+
+GVariant *mm_network_timezone_get_dictionary (MMNetworkTimezone *self);
+
+G_END_DECLS
+
+#endif /* MM_NETWORK_TIMEZONE_H */
diff --git a/libmm-glib/mm-simple-connect-properties.c b/libmm-glib/mm-simple-connect-properties.c
new file mode 100644
index 00000000..d36ee00e
--- /dev/null
+++ b/libmm-glib/mm-simple-connect-properties.c
@@ -0,0 +1,582 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2011 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <string.h>
+
+#include "mm-errors-types.h"
+#include "mm-common-helpers.h"
+#include "mm-simple-connect-properties.h"
+
+G_DEFINE_TYPE (MMSimpleConnectProperties, mm_simple_connect_properties, G_TYPE_OBJECT);
+
+#define PROPERTY_PIN "pin"
+#define PROPERTY_OPERATOR_ID "operator-id"
+#define PROPERTY_BANDS "bands"
+#define PROPERTY_ALLOWED_MODES "allowed-modes"
+#define PROPERTY_PREFERRED_MODE "preferred-mode"
+
+struct _MMSimpleConnectPropertiesPrivate {
+ /* PIN */
+ gchar *pin;
+ /* Operator ID */
+ gchar *operator_id;
+ /* Bands */
+ gboolean bands_set;
+ MMModemBand *bands;
+ guint n_bands;
+ /* Modes */
+ gboolean allowed_modes_set;
+ MMModemMode allowed_modes;
+ MMModemMode preferred_mode;
+ /* Bearer properties */
+ MMBearerProperties *bearer_properties;
+};
+
+/*****************************************************************************/
+
+void
+mm_simple_connect_properties_set_pin (MMSimpleConnectProperties *self,
+ const gchar *pin)
+{
+ g_return_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self));
+
+ g_free (self->priv->pin);
+ self->priv->pin = g_strdup (pin);
+}
+
+void
+mm_simple_connect_properties_set_operator_id (MMSimpleConnectProperties *self,
+ const gchar *operator_id)
+{
+ g_return_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self));
+
+ g_free (self->priv->operator_id);
+ self->priv->operator_id = g_strdup (operator_id);
+}
+
+void
+mm_simple_connect_properties_set_bands (MMSimpleConnectProperties *self,
+ const MMModemBand *bands,
+ guint n_bands)
+{
+ g_return_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self));
+
+ g_free (self->priv->bands);
+ self->priv->n_bands = n_bands;
+ self->priv->bands = g_new (MMModemBand, self->priv->n_bands);
+ memcpy (self->priv->bands,
+ bands,
+ sizeof (MMModemBand) * self->priv->n_bands);
+ self->priv->bands_set = TRUE;
+}
+
+void
+mm_simple_connect_properties_set_allowed_modes (MMSimpleConnectProperties *self,
+ MMModemMode allowed,
+ MMModemMode preferred)
+{
+ g_return_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self));
+
+ self->priv->allowed_modes = allowed;
+ self->priv->preferred_mode = preferred;
+ self->priv->allowed_modes_set = TRUE;
+}
+
+void
+mm_simple_connect_properties_set_apn (MMSimpleConnectProperties *self,
+ const gchar *apn)
+{
+ g_return_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self));
+
+ mm_bearer_properties_set_apn (self->priv->bearer_properties,
+ apn);
+}
+
+void
+mm_simple_connect_properties_set_user (MMSimpleConnectProperties *self,
+ const gchar *user)
+{
+ g_return_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self));
+
+ mm_bearer_properties_set_user (self->priv->bearer_properties,
+ user);
+}
+
+void
+mm_simple_connect_properties_set_password (MMSimpleConnectProperties *self,
+ const gchar *password)
+{
+ g_return_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self));
+
+ mm_bearer_properties_set_password (self->priv->bearer_properties,
+ password);
+}
+
+void
+mm_simple_connect_properties_set_ip_type (MMSimpleConnectProperties *self,
+ MMBearerIpFamily ip_type)
+{
+ g_return_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self));
+
+ mm_bearer_properties_set_ip_type (self->priv->bearer_properties,
+ ip_type);
+}
+
+void
+mm_simple_connect_properties_set_allow_roaming (MMSimpleConnectProperties *self,
+ gboolean allow_roaming)
+{
+ g_return_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self));
+
+ mm_bearer_properties_set_allow_roaming (self->priv->bearer_properties,
+ allow_roaming);
+}
+
+void
+mm_simple_connect_properties_set_number (MMSimpleConnectProperties *self,
+ const gchar *number)
+{
+ g_return_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self));
+
+ mm_bearer_properties_set_number (self->priv->bearer_properties,
+ number);
+}
+
+/*****************************************************************************/
+
+MMBearerProperties *
+mm_simple_connect_properties_get_bearer_properties (MMSimpleConnectProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self), NULL);
+
+ return g_object_ref (self->priv->bearer_properties);
+}
+
+const gchar *
+mm_simple_connect_properties_get_pin (MMSimpleConnectProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self), NULL);
+
+ return self->priv->pin;
+}
+
+const gchar *
+mm_simple_connect_properties_get_operator_id (MMSimpleConnectProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self), NULL);
+
+ return self->priv->operator_id;
+}
+
+gboolean
+mm_simple_connect_properties_get_bands (MMSimpleConnectProperties *self,
+ const MMModemBand **bands,
+ guint *n_bands)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self), FALSE);
+ g_return_val_if_fail (bands != NULL, FALSE);
+ g_return_val_if_fail (n_bands != NULL, FALSE);
+
+ if (self->priv->bands_set) {
+ *bands = self->priv->bands;
+ *n_bands = self->priv->n_bands;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+mm_simple_connect_properties_get_allowed_modes (MMSimpleConnectProperties *self,
+ MMModemMode *allowed,
+ MMModemMode *preferred)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self), FALSE);
+ g_return_val_if_fail (allowed != NULL, FALSE);
+ g_return_val_if_fail (preferred != NULL, FALSE);
+
+ if (self->priv->allowed_modes_set) {
+ *allowed = self->priv->allowed_modes;
+ *preferred = self->priv->preferred_mode;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+const gchar *
+mm_simple_connect_properties_get_apn (MMSimpleConnectProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self), NULL);
+
+ return mm_bearer_properties_get_apn (self->priv->bearer_properties);
+}
+
+const gchar *
+mm_simple_connect_properties_get_user (MMSimpleConnectProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self), NULL);
+
+ return mm_bearer_properties_get_user (self->priv->bearer_properties);
+}
+
+const gchar *
+mm_simple_connect_properties_get_password (MMSimpleConnectProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self), NULL);
+
+ return mm_bearer_properties_get_password (self->priv->bearer_properties);
+}
+
+MMBearerIpFamily
+mm_simple_connect_properties_get_ip_type (MMSimpleConnectProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self), MM_BEARER_IP_FAMILY_UNKNOWN);
+
+ return mm_bearer_properties_get_ip_type (self->priv->bearer_properties);
+}
+
+gboolean
+mm_simple_connect_properties_get_allow_roaming (MMSimpleConnectProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self), FALSE);
+
+ return mm_bearer_properties_get_allow_roaming (self->priv->bearer_properties);
+}
+
+const gchar *
+mm_simple_connect_properties_get_number (MMSimpleConnectProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self), NULL);
+
+ return mm_bearer_properties_get_number (self->priv->bearer_properties);
+}
+
+/*****************************************************************************/
+
+GVariant *
+mm_simple_connect_properties_get_dictionary (MMSimpleConnectProperties *self)
+{
+ GVariantBuilder builder;
+ GVariantIter iter;
+ gchar *key;
+ GVariant *value;
+ GVariant *bearer_properties_dictionary;
+
+ /* We do allow NULL */
+ if (!self)
+ return NULL;
+
+ g_return_val_if_fail (MM_IS_SIMPLE_CONNECT_PROPERTIES (self), NULL);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+ if (self->priv->pin)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_PIN,
+ g_variant_new_string (self->priv->pin));
+
+ if (self->priv->operator_id)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_OPERATOR_ID,
+ g_variant_new_string (self->priv->operator_id));
+
+ if (self->priv->bands)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_BANDS,
+ mm_common_bands_array_to_variant (self->priv->bands,
+ self->priv->n_bands));
+
+ if (self->priv->allowed_modes_set) {
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_ALLOWED_MODES,
+ g_variant_new_uint32 (self->priv->allowed_modes));
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_PREFERRED_MODE,
+ g_variant_new_uint32 (self->priv->preferred_mode));
+ }
+
+ /* Merge dictionaries */
+ bearer_properties_dictionary = mm_bearer_properties_get_dictionary (self->priv->bearer_properties);
+ g_variant_iter_init (&iter, bearer_properties_dictionary);
+ while (g_variant_iter_next (&iter, "{sv}", &key, &value)) {
+ g_variant_builder_add (&builder,
+ "{sv}",
+ key,
+ value);
+ g_variant_unref (value);
+ g_free (key);
+ }
+ g_variant_unref (bearer_properties_dictionary);
+
+ return g_variant_ref_sink (g_variant_builder_end (&builder));
+}
+
+/*****************************************************************************/
+
+typedef struct {
+ MMSimpleConnectProperties *properties;
+ GError *error;
+ gchar *allowed_modes_str;
+ gchar *preferred_mode_str;
+} ParseKeyValueContext;
+
+static gboolean
+key_value_foreach (const gchar *key,
+ const gchar *value,
+ ParseKeyValueContext *ctx)
+{
+ /* First, check if we can consume this as bearer properties */
+ if (mm_bearer_properties_consume_string (ctx->properties->priv->bearer_properties,
+ key, value,
+ NULL))
+ return TRUE;
+
+ if (g_str_equal (key, PROPERTY_PIN))
+ mm_simple_connect_properties_set_pin (ctx->properties, value);
+ else if (g_str_equal (key, PROPERTY_OPERATOR_ID))
+ mm_simple_connect_properties_set_operator_id (ctx->properties, value);
+ else if (g_str_equal (key, PROPERTY_BANDS)) {
+ MMModemBand *bands = NULL;
+ guint n_bands = 0;
+
+ mm_common_get_bands_from_string (value, &bands, &n_bands, &ctx->error);
+ if (!ctx->error) {
+ mm_simple_connect_properties_set_bands (ctx->properties, bands, n_bands);
+ g_free (bands);
+ }
+ } else if (g_str_equal (key, PROPERTY_ALLOWED_MODES)) {
+ ctx->allowed_modes_str = g_strdup (value);
+ } else if (g_str_equal (key, PROPERTY_PREFERRED_MODE)) {
+ ctx->preferred_mode_str = g_strdup (value);
+ } else {
+ ctx->error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid properties string, unexpected key '%s'",
+ key);
+ }
+
+ return !ctx->error;
+}
+
+MMSimpleConnectProperties *
+mm_simple_connect_properties_new_from_string (const gchar *str,
+ GError **error)
+{
+ ParseKeyValueContext ctx;
+
+ ctx.error = NULL;
+ ctx.allowed_modes_str = NULL;
+ ctx.preferred_mode_str = NULL;
+ ctx.properties = mm_simple_connect_properties_new ();
+
+ mm_common_parse_key_value_string (str,
+ &ctx.error,
+ (MMParseKeyValueForeachFn)key_value_foreach,
+ &ctx);
+
+ /* If error, destroy the object */
+ if (ctx.error) {
+ g_propagate_error (error, ctx.error);
+ g_object_unref (ctx.properties);
+ ctx.properties = NULL;
+ }
+ else if (ctx.allowed_modes_str || ctx.preferred_mode_str) {
+ MMModemMode allowed_modes;
+ MMModemMode preferred_mode;
+
+ allowed_modes = (ctx.allowed_modes_str ?
+ mm_common_get_modes_from_string (ctx.allowed_modes_str,
+ &ctx.error) :
+ MM_MODEM_MODE_ANY);
+ if (!ctx.error) {
+ preferred_mode = (ctx.preferred_mode_str ?
+ mm_common_get_modes_from_string (ctx.preferred_mode_str,
+ &ctx.error) :
+ MM_MODEM_MODE_NONE);
+ }
+
+ if (ctx.error) {
+ g_propagate_error (error, ctx.error);
+ g_object_unref (ctx.properties);
+ ctx.properties = NULL;
+ } else {
+ mm_simple_connect_properties_set_allowed_modes (
+ ctx.properties,
+ allowed_modes,
+ preferred_mode);
+ }
+ }
+
+ g_free (ctx.allowed_modes_str);
+ g_free (ctx.preferred_mode_str);
+
+ return ctx.properties;
+}
+
+/*****************************************************************************/
+
+MMSimpleConnectProperties *
+mm_simple_connect_properties_new_from_dictionary (GVariant *dictionary,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ GVariantIter iter;
+ gchar *key;
+ GVariant *value;
+ MMSimpleConnectProperties *properties;
+ GVariant *allowed_modes_variant = NULL;
+ GVariant *preferred_mode_variant = NULL;
+
+ properties = mm_simple_connect_properties_new ();
+ if (!dictionary)
+ return properties;
+
+ if (!g_variant_is_of_type (dictionary, G_VARIANT_TYPE ("a{sv}"))) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create Simple Connect properties from dictionary: "
+ "invalid variant type received");
+ g_object_unref (properties);
+ return NULL;
+ }
+
+ g_variant_iter_init (&iter, dictionary);
+ while (!inner_error &&
+ g_variant_iter_next (&iter, "{sv}", &key, &value)) {
+
+ /* First, check if we can consume this as bearer properties */
+ if (!mm_bearer_properties_consume_variant (properties->priv->bearer_properties,
+ key, value,
+ NULL)) {
+ if (g_str_equal (key, PROPERTY_PIN))
+ mm_simple_connect_properties_set_pin (
+ properties,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_OPERATOR_ID))
+ mm_simple_connect_properties_set_operator_id (
+ properties,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_BANDS)) {
+ GArray *array;
+
+ array = mm_common_bands_variant_to_garray (value);
+ mm_simple_connect_properties_set_bands (
+ properties,
+ (MMModemBand *)array->data,
+ array->len);
+ g_array_unref (array);
+ } else if (g_str_equal (key, PROPERTY_ALLOWED_MODES))
+ allowed_modes_variant = g_variant_ref (value);
+ else if (g_str_equal (key, PROPERTY_PREFERRED_MODE))
+ preferred_mode_variant = g_variant_ref (value);
+ else {
+ /* Set inner error, will stop the loop */
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid properties dictionary, unexpected key '%s'",
+ key);
+ }
+ }
+
+ g_free (key);
+ g_variant_unref (value);
+ }
+
+ /* If error, destroy the object */
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ g_object_unref (properties);
+ properties = NULL;
+ }
+ /* If we got allowed modes variant, check if we got preferred mode */
+ else if (allowed_modes_variant) {
+ mm_simple_connect_properties_set_allowed_modes (
+ properties,
+ g_variant_get_uint32 (allowed_modes_variant),
+ (preferred_mode_variant ?
+ g_variant_get_uint32 (preferred_mode_variant) :
+ MM_MODEM_MODE_NONE));
+ }
+ /* If we only got preferred mode, assume allowed is ANY */
+ else if (preferred_mode_variant) {
+ mm_simple_connect_properties_set_allowed_modes (
+ properties,
+ MM_MODEM_MODE_ANY,
+ g_variant_get_uint32 (preferred_mode_variant));
+ }
+
+ /* Cleanup last things before exiting */
+ if (allowed_modes_variant)
+ g_variant_unref (allowed_modes_variant);
+ if (preferred_mode_variant)
+ g_variant_unref (preferred_mode_variant);
+
+ return properties;
+}
+
+/*****************************************************************************/
+
+MMSimpleConnectProperties *
+mm_simple_connect_properties_new (void)
+{
+ return (MM_SIMPLE_CONNECT_PROPERTIES (
+ g_object_new (MM_TYPE_SIMPLE_CONNECT_PROPERTIES, NULL)));
+}
+
+static void
+mm_simple_connect_properties_init (MMSimpleConnectProperties *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
+ MM_TYPE_SIMPLE_CONNECT_PROPERTIES,
+ MMSimpleConnectPropertiesPrivate);
+
+ /* Some defaults */
+ self->priv->bearer_properties = mm_bearer_properties_new ();
+ self->priv->allowed_modes = MM_MODEM_MODE_ANY;
+ self->priv->preferred_mode = MM_MODEM_MODE_NONE;
+ self->priv->bands = g_new (MMModemBand, 1);
+ self->priv->bands[0] = MM_MODEM_BAND_UNKNOWN;
+ self->priv->n_bands = 1;
+}
+
+static void
+finalize (GObject *object)
+{
+ MMSimpleConnectProperties *self = MM_SIMPLE_CONNECT_PROPERTIES (object);
+
+ g_free (self->priv->pin);
+ g_free (self->priv->operator_id);
+ g_free (self->priv->bands);
+ g_object_unref (self->priv->bearer_properties);
+
+ G_OBJECT_CLASS (mm_simple_connect_properties_parent_class)->finalize (object);
+}
+
+static void
+mm_simple_connect_properties_class_init (MMSimpleConnectPropertiesClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMSimpleConnectPropertiesPrivate));
+
+ object_class->finalize = finalize;
+}
diff --git a/libmm-glib/mm-simple-connect-properties.h b/libmm-glib/mm-simple-connect-properties.h
new file mode 100644
index 00000000..2a2e72f0
--- /dev/null
+++ b/libmm-glib/mm-simple-connect-properties.h
@@ -0,0 +1,98 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2011 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#ifndef MM_SIMPLE_CONNECT_PROPERTIES_H
+#define MM_SIMPLE_CONNECT_PROPERTIES_H
+
+#include <ModemManager.h>
+#include <glib-object.h>
+
+#include "mm-bearer-properties.h"
+
+G_BEGIN_DECLS
+
+#define MM_TYPE_SIMPLE_CONNECT_PROPERTIES (mm_simple_connect_properties_get_type ())
+#define MM_SIMPLE_CONNECT_PROPERTIES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SIMPLE_CONNECT_PROPERTIES, MMSimpleConnectProperties))
+#define MM_SIMPLE_CONNECT_PROPERTIES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SIMPLE_CONNECT_PROPERTIES, MMSimpleConnectPropertiesClass))
+#define MM_IS_SIMPLE_CONNECT_PROPERTIES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SIMPLE_CONNECT_PROPERTIES))
+#define MM_IS_SIMPLE_CONNECT_PROPERTIES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SIMPLE_CONNECT_PROPERTIES))
+#define MM_SIMPLE_CONNECT_PROPERTIES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SIMPLE_CONNECT_PROPERTIES, MMSimpleConnectPropertiesClass))
+
+typedef struct _MMSimpleConnectProperties MMSimpleConnectProperties;
+typedef struct _MMSimpleConnectPropertiesClass MMSimpleConnectPropertiesClass;
+typedef struct _MMSimpleConnectPropertiesPrivate MMSimpleConnectPropertiesPrivate;
+
+struct _MMSimpleConnectProperties {
+ GObject parent;
+ MMSimpleConnectPropertiesPrivate *priv;
+};
+
+struct _MMSimpleConnectPropertiesClass {
+ GObjectClass parent;
+};
+
+GType mm_simple_connect_properties_get_type (void);
+
+MMSimpleConnectProperties *mm_simple_connect_properties_new (void);
+MMSimpleConnectProperties *mm_simple_connect_properties_new_from_string (const gchar *str,
+ GError **error);
+MMSimpleConnectProperties *mm_simple_connect_properties_new_from_dictionary (GVariant *dictionary,
+ GError **error);
+
+void mm_simple_connect_properties_set_pin (MMSimpleConnectProperties *properties,
+ const gchar *pin);
+void mm_simple_connect_properties_set_operator_id (MMSimpleConnectProperties *properties,
+ const gchar *operator_id);
+void mm_simple_connect_properties_set_bands (MMSimpleConnectProperties *properties,
+ const MMModemBand *bands,
+ guint n_bands);
+void mm_simple_connect_properties_set_allowed_modes (MMSimpleConnectProperties *properties,
+ MMModemMode allowed,
+ MMModemMode preferred);
+void mm_simple_connect_properties_set_apn (MMSimpleConnectProperties *properties,
+ const gchar *apn);
+void mm_simple_connect_properties_set_user (MMSimpleConnectProperties *properties,
+ const gchar *user);
+void mm_simple_connect_properties_set_password (MMSimpleConnectProperties *properties,
+ const gchar *password);
+void mm_simple_connect_properties_set_ip_type (MMSimpleConnectProperties *properties,
+ MMBearerIpFamily ip_type);
+void mm_simple_connect_properties_set_allow_roaming (MMSimpleConnectProperties *properties,
+ gboolean allow_roaming);
+void mm_simple_connect_properties_set_number (MMSimpleConnectProperties *properties,
+ const gchar *number);
+
+const gchar *mm_simple_connect_properties_get_pin (MMSimpleConnectProperties *properties);
+const gchar *mm_simple_connect_properties_get_operator_id (MMSimpleConnectProperties *properties);
+gboolean mm_simple_connect_properties_get_bands (MMSimpleConnectProperties *properties,
+ const MMModemBand **bands,
+ guint *n_bands);
+gboolean mm_simple_connect_properties_get_allowed_modes (MMSimpleConnectProperties *properties,
+ MMModemMode *allowed,
+ MMModemMode *preferred);
+const gchar *mm_simple_connect_properties_get_apn (MMSimpleConnectProperties *properties);
+const gchar *mm_simple_connect_properties_get_user (MMSimpleConnectProperties *properties);
+const gchar *mm_simple_connect_properties_get_password (MMSimpleConnectProperties *properties);
+MMBearerIpFamily mm_simple_connect_properties_get_ip_type (MMSimpleConnectProperties *properties);
+gboolean mm_simple_connect_properties_get_allow_roaming (MMSimpleConnectProperties *properties);
+const gchar *mm_simple_connect_properties_get_number (MMSimpleConnectProperties *properties);
+
+MMBearerProperties *mm_simple_connect_properties_get_bearer_properties (MMSimpleConnectProperties *properties);
+
+GVariant *mm_simple_connect_properties_get_dictionary (MMSimpleConnectProperties *self);
+
+G_END_DECLS
+
+#endif /* MM_SIMPLE_CONNECT_PROPERTIES_H */
diff --git a/libmm-glib/mm-simple-status.c b/libmm-glib/mm-simple-status.c
new file mode 100644
index 00000000..e54bcb80
--- /dev/null
+++ b/libmm-glib/mm-simple-status.c
@@ -0,0 +1,599 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2011 Google, Inc.
+ */
+
+#include <string.h>
+
+#include "mm-enums-types.h"
+#include "mm-errors-types.h"
+#include "mm-common-helpers.h"
+#include "mm-simple-status.h"
+
+#define SID_UNKNOWN 99999
+#define NID_UNKNOWN 99999
+
+G_DEFINE_TYPE (MMSimpleStatus, mm_simple_status, G_TYPE_OBJECT);
+
+enum {
+ PROP_0,
+ PROP_STATE,
+ PROP_SIGNAL_QUALITY,
+ PROP_BANDS,
+ PROP_ACCESS_TECHNOLOGIES,
+ PROP_3GPP_REGISTRATION_STATE,
+ PROP_3GPP_OPERATOR_CODE,
+ PROP_3GPP_OPERATOR_NAME,
+ PROP_CDMA_CDMA1X_REGISTRATION_STATE,
+ PROP_CDMA_EVDO_REGISTRATION_STATE,
+ PROP_CDMA_SID,
+ PROP_CDMA_NID,
+ PROP_LAST
+};
+
+static GParamSpec *properties[PROP_LAST];
+
+struct _MMSimpleStatusPrivate {
+ /* <--- From the Modem interface ---> */
+ /* Overall modem state, signature 'u' */
+ MMModemState state;
+ /* Signal quality, given only when registered, signature '(ub)' */
+ GVariant *signal_quality;
+ /* List of bands, given only when registered, signature: au */
+ GVariant *bands;
+ GArray *bands_array;
+ /* Access technologies, given only when registered, signature: u */
+ MMModemAccessTechnology access_technologies;
+
+ /* <--- From the Modem 3GPP interface ---> */
+ /* 3GPP registration state, signature 'u' */
+ MMModem3gppRegistrationState modem_3gpp_registration_state;
+ /* 3GPP operator code, given only when registered, signature 's' */
+ gchar *modem_3gpp_operator_code;
+ /* 3GPP operator name, given only when registered, signature 's' */
+ gchar *modem_3gpp_operator_name;
+
+ /* <--- From the Modem CDMA interface ---> */
+ /* CDMA/CDMA1x registration state, signature 'u' */
+ MMModemCdmaRegistrationState modem_cdma_cdma1x_registration_state;
+ /* CDMA/EV-DO registration state, signature 'u' */
+ MMModemCdmaRegistrationState modem_cdma_evdo_registration_state;
+ /* SID, signature 'u' */
+ guint modem_cdma_sid;
+ /* NID, signature 'u' */
+ guint modem_cdma_nid;
+};
+
+/*****************************************************************************/
+
+MMModemState
+mm_simple_status_get_state (MMSimpleStatus *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_STATUS (self), MM_MODEM_STATE_UNKNOWN);
+
+ return self->priv->state;
+}
+
+guint32
+mm_simple_status_get_signal_quality (MMSimpleStatus *self,
+ gboolean *recent)
+{
+ guint32 signal_quality = 0;
+ gboolean signal_quality_recent = FALSE;
+
+ g_return_val_if_fail (MM_IS_SIMPLE_STATUS (self), 0);
+
+ if (self->priv->signal_quality) {
+ g_variant_get (self->priv->signal_quality,
+ "(ub)",
+ &signal_quality,
+ &signal_quality_recent);
+ }
+
+ if (recent)
+ *recent = signal_quality_recent;
+ return signal_quality;
+}
+
+void
+mm_simple_status_get_bands (MMSimpleStatus *self,
+ const MMModemBand **bands,
+ guint *n_bands)
+{
+ g_return_if_fail (MM_IS_SIMPLE_STATUS (self));
+
+ if (!self->priv->bands_array)
+ self->priv->bands_array = mm_common_bands_variant_to_garray (self->priv->bands);
+
+ *n_bands = self->priv->bands_array->len;
+ *bands = (const MMModemBand *)self->priv->bands_array->data;
+}
+
+MMModemAccessTechnology
+mm_simple_status_get_access_technologies (MMSimpleStatus *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_STATUS (self), MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
+
+ return self->priv->access_technologies;
+}
+
+MMModem3gppRegistrationState
+mm_simple_status_get_3gpp_registration_state (MMSimpleStatus *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_STATUS (self), MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN);
+
+ return self->priv->modem_3gpp_registration_state;
+}
+
+const gchar *
+mm_simple_status_get_3gpp_operator_code (MMSimpleStatus *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_STATUS (self), NULL);
+
+ return self->priv->modem_3gpp_operator_code;
+}
+
+const gchar *
+mm_simple_status_get_3gpp_operator_name (MMSimpleStatus *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_STATUS (self), NULL);
+
+ return self->priv->modem_3gpp_operator_name;
+}
+
+MMModemCdmaRegistrationState
+mm_simple_status_get_cdma_cdma1x_registration_state (MMSimpleStatus *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_STATUS (self), MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
+
+ return self->priv->modem_cdma_cdma1x_registration_state;
+}
+
+MMModemCdmaRegistrationState
+mm_simple_status_get_cdma_evdo_registration_state (MMSimpleStatus *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_STATUS (self), MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
+
+ return self->priv->modem_cdma_evdo_registration_state;
+}
+
+guint
+mm_simple_status_get_cdma_sid (MMSimpleStatus *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_STATUS (self), 0);
+
+ return self->priv->modem_cdma_sid;
+}
+
+guint
+mm_simple_status_get_cdma_nid (MMSimpleStatus *self)
+{
+ g_return_val_if_fail (MM_IS_SIMPLE_STATUS (self), 0);
+
+ return self->priv->modem_cdma_nid;
+}
+
+/*****************************************************************************/
+
+GVariant *
+mm_simple_status_get_dictionary (MMSimpleStatus *self)
+{
+ GVariantBuilder builder;
+
+ /* Allow NULL */
+ if (!self)
+ return NULL;
+
+ g_return_val_if_fail (MM_IS_SIMPLE_STATUS (self), NULL);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+ g_variant_builder_add (&builder,
+ "{sv}",
+ MM_SIMPLE_PROPERTY_STATE,
+ g_variant_new_uint32 (self->priv->state));
+
+ /* Next ones, only when registered */
+ if (self->priv->state >= MM_MODEM_STATE_REGISTERED) {
+ g_variant_builder_add (&builder,
+ "{sv}",
+ MM_SIMPLE_PROPERTY_SIGNAL_QUALITY,
+ self->priv->signal_quality);
+ g_variant_builder_add (&builder,
+ "{sv}",
+ MM_SIMPLE_PROPERTY_BANDS,
+ self->priv->bands);
+ g_variant_builder_add (&builder,
+ "{sv}",
+ MM_SIMPLE_PROPERTY_ACCESS_TECHNOLOGIES,
+ g_variant_new_uint32 (self->priv->access_technologies));
+
+ g_variant_builder_add (&builder,
+ "{sv}",
+ MM_SIMPLE_PROPERTY_3GPP_REGISTRATION_STATE,
+ g_variant_new_uint32 (self->priv->modem_3gpp_registration_state));
+ if (self->priv->modem_3gpp_operator_code)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ MM_SIMPLE_PROPERTY_3GPP_OPERATOR_CODE,
+ g_variant_new_string (self->priv->modem_3gpp_operator_code));
+ if (self->priv->modem_3gpp_operator_name)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ MM_SIMPLE_PROPERTY_3GPP_OPERATOR_NAME,
+ g_variant_new_string (self->priv->modem_3gpp_operator_name));
+
+ if (self->priv->modem_cdma_cdma1x_registration_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) {
+ g_variant_builder_add (&builder,
+ "{sv}",
+ MM_SIMPLE_PROPERTY_CDMA_CDMA1X_REGISTRATION_STATE,
+ g_variant_new_uint32 (self->priv->modem_cdma_cdma1x_registration_state));
+ if (self->priv->modem_cdma_sid != SID_UNKNOWN)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ MM_SIMPLE_PROPERTY_CDMA_SID,
+ g_variant_new_uint32 (self->priv->modem_cdma_sid));
+ if (self->priv->modem_cdma_nid != NID_UNKNOWN)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ MM_SIMPLE_PROPERTY_CDMA_NID,
+ g_variant_new_uint32 (self->priv->modem_cdma_nid));
+ }
+ if (self->priv->modem_cdma_evdo_registration_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ MM_SIMPLE_PROPERTY_CDMA_EVDO_REGISTRATION_STATE,
+ g_variant_new_uint32 (self->priv->modem_cdma_evdo_registration_state));
+
+ }
+
+ return g_variant_ref_sink (g_variant_builder_end (&builder));
+}
+
+/*****************************************************************************/
+
+MMSimpleStatus *
+mm_simple_status_new_from_dictionary (GVariant *dictionary,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ GVariantIter iter;
+ gchar *key;
+ GVariant *value;
+ MMSimpleStatus *properties;
+
+ properties = mm_simple_status_new ();
+ if (!dictionary)
+ return properties;
+
+ if (!g_variant_is_of_type (dictionary, G_VARIANT_TYPE ("a{sv}"))) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create Simple status from dictionary: "
+ "invalid variant type received");
+ g_object_unref (properties);
+ return NULL;
+ }
+
+ g_variant_iter_init (&iter, dictionary);
+ while (!inner_error &&
+ g_variant_iter_next (&iter, "{sv}", &key, &value)) {
+ /* Note: we could do a more efficient matching by checking the variant type
+ * and just g_object_set()-ing they specific 'key' and value, but we do want
+ * to check which input keys we receive, in order to propagate the error.
+ */
+ if (g_str_equal (key, MM_SIMPLE_PROPERTY_STATE) ||
+ g_str_equal (key, MM_SIMPLE_PROPERTY_ACCESS_TECHNOLOGIES) ||
+ g_str_equal (key, MM_SIMPLE_PROPERTY_3GPP_REGISTRATION_STATE) ||
+ g_str_equal (key, MM_SIMPLE_PROPERTY_CDMA_CDMA1X_REGISTRATION_STATE) ||
+ g_str_equal (key, MM_SIMPLE_PROPERTY_CDMA_EVDO_REGISTRATION_STATE) ||
+ g_str_equal (key, MM_SIMPLE_PROPERTY_CDMA_SID) ||
+ g_str_equal (key, MM_SIMPLE_PROPERTY_CDMA_NID)) {
+ /* uint properties */
+ g_object_set (properties,
+ key, g_variant_get_uint32 (value),
+ NULL);
+ } else if (g_str_equal (key, MM_SIMPLE_PROPERTY_3GPP_OPERATOR_CODE) ||
+ g_str_equal (key, MM_SIMPLE_PROPERTY_3GPP_OPERATOR_NAME)) {
+ /* string properties */
+ g_object_set (properties,
+ key, g_variant_get_string (value, NULL),
+ NULL);
+ } else if (g_str_equal (key, MM_SIMPLE_PROPERTY_BANDS) ||
+ g_str_equal (key, MM_SIMPLE_PROPERTY_SIGNAL_QUALITY)) {
+ /* remaining complex types, as variant */
+ g_object_set (properties,
+ key, value,
+ NULL);
+ } else {
+ /* Set inner error, will stop the loop */
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid status dictionary, unexpected key '%s'",
+ key);
+ }
+
+ g_free (key);
+ g_variant_unref (value);
+ }
+
+ /* If error, destroy the object */
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ g_object_unref (properties);
+ properties = NULL;
+ }
+
+ return properties;
+}
+
+/*****************************************************************************/
+
+MMSimpleStatus *
+mm_simple_status_new (void)
+{
+ return (MM_SIMPLE_STATUS (
+ g_object_new (MM_TYPE_SIMPLE_STATUS, NULL)));
+}
+
+static void
+set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MMSimpleStatus *self = MM_SIMPLE_STATUS (object);
+
+ switch (prop_id) {
+ case PROP_STATE:
+ self->priv->state = g_value_get_enum (value);
+ break;
+ case PROP_SIGNAL_QUALITY:
+ if (self->priv->signal_quality)
+ g_variant_unref (self->priv->signal_quality);
+ self->priv->signal_quality = g_value_dup_variant (value);
+ break;
+ case PROP_BANDS:
+ if (self->priv->bands)
+ g_variant_unref (self->priv->bands);
+ if (self->priv->bands_array) {
+ g_array_unref (self->priv->bands_array);
+ self->priv->bands_array = NULL;
+ }
+ self->priv->bands = g_value_dup_variant (value);
+ break;
+ case PROP_ACCESS_TECHNOLOGIES:
+ self->priv->access_technologies = g_value_get_flags (value);
+ break;
+ case PROP_3GPP_REGISTRATION_STATE:
+ self->priv->modem_3gpp_registration_state = g_value_get_enum (value);
+ break;
+ case PROP_3GPP_OPERATOR_CODE:
+ g_free (self->priv->modem_3gpp_operator_code);
+ self->priv->modem_3gpp_operator_code = g_value_dup_string (value);
+ break;
+ case PROP_3GPP_OPERATOR_NAME:
+ g_free (self->priv->modem_3gpp_operator_name);
+ self->priv->modem_3gpp_operator_name = g_value_dup_string (value);
+ break;
+ case PROP_CDMA_CDMA1X_REGISTRATION_STATE:
+ self->priv->modem_cdma_cdma1x_registration_state = g_value_get_enum (value);
+ break;
+ case PROP_CDMA_EVDO_REGISTRATION_STATE:
+ self->priv->modem_cdma_evdo_registration_state = g_value_get_enum (value);
+ break;
+ case PROP_CDMA_SID:
+ self->priv->modem_cdma_sid = g_value_get_uint (value);
+ break;
+ case PROP_CDMA_NID:
+ self->priv->modem_cdma_nid = g_value_get_uint (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)
+{
+ MMSimpleStatus *self = MM_SIMPLE_STATUS (object);
+
+ switch (prop_id) {
+ case PROP_STATE:
+ g_value_set_enum (value, self->priv->state);
+ break;
+ case PROP_SIGNAL_QUALITY:
+ g_value_set_variant (value, self->priv->signal_quality);
+ break;
+ case PROP_BANDS:
+ g_value_set_variant (value, self->priv->bands);
+ break;
+ case PROP_ACCESS_TECHNOLOGIES:
+ g_value_set_flags (value, self->priv->access_technologies);
+ break;
+ case PROP_3GPP_REGISTRATION_STATE:
+ g_value_set_enum (value, self->priv->modem_3gpp_registration_state);
+ break;
+ case PROP_3GPP_OPERATOR_CODE:
+ g_value_set_string (value, self->priv->modem_3gpp_operator_code);
+ break;
+ case PROP_3GPP_OPERATOR_NAME:
+ g_value_set_string (value, self->priv->modem_3gpp_operator_name);
+ break;
+ case PROP_CDMA_CDMA1X_REGISTRATION_STATE:
+ g_value_set_enum (value, self->priv->modem_cdma_cdma1x_registration_state);
+ break;
+ case PROP_CDMA_EVDO_REGISTRATION_STATE:
+ g_value_set_enum (value, self->priv->modem_cdma_evdo_registration_state);
+ break;
+ case PROP_CDMA_SID:
+ g_value_set_uint (value, self->priv->modem_cdma_sid);
+ break;
+ case PROP_CDMA_NID:
+ g_value_set_uint (value, self->priv->modem_cdma_nid);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+mm_simple_status_init (MMSimpleStatus *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
+ MM_TYPE_SIMPLE_STATUS,
+ MMSimpleStatusPrivate);
+
+ /* Some defaults */
+ self->priv->state = MM_MODEM_STATE_UNKNOWN;
+ self->priv->access_technologies = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
+ self->priv->modem_3gpp_registration_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
+ self->priv->bands = g_variant_ref_sink (mm_common_build_bands_unknown ());
+ self->priv->signal_quality = g_variant_ref_sink (g_variant_new ("(ub)", 0, 0));
+ self->priv->modem_cdma_cdma1x_registration_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
+ self->priv->modem_cdma_evdo_registration_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
+ self->priv->modem_cdma_sid = SID_UNKNOWN;
+ self->priv->modem_cdma_nid = NID_UNKNOWN;
+}
+
+static void
+finalize (GObject *object)
+{
+ MMSimpleStatus *self = MM_SIMPLE_STATUS (object);
+
+ g_variant_unref (self->priv->signal_quality);
+ g_variant_unref (self->priv->bands);
+ if (self->priv->bands_array)
+ g_array_unref (self->priv->bands_array);
+ g_free (self->priv->modem_3gpp_operator_code);
+ g_free (self->priv->modem_3gpp_operator_name);
+
+ G_OBJECT_CLASS (mm_simple_status_parent_class)->finalize (object);
+}
+
+static void
+mm_simple_status_class_init (MMSimpleStatusClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMSimpleStatusPrivate));
+
+ /* Virtual methods */
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+ object_class->finalize = finalize;
+
+ properties[PROP_STATE] =
+ g_param_spec_enum (MM_SIMPLE_PROPERTY_STATE,
+ "State",
+ "State of the modem",
+ MM_TYPE_MODEM_STATE,
+ MM_MODEM_STATE_UNKNOWN,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_STATE, properties[PROP_STATE]);
+
+ properties[PROP_SIGNAL_QUALITY] =
+ g_param_spec_variant (MM_SIMPLE_PROPERTY_SIGNAL_QUALITY,
+ "Signal quality",
+ "Signal quality reported by the modem",
+ G_VARIANT_TYPE ("(ub)"),
+ NULL,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_SIGNAL_QUALITY, properties[PROP_SIGNAL_QUALITY]);
+
+ properties[PROP_BANDS] =
+ g_param_spec_variant (MM_SIMPLE_PROPERTY_BANDS,
+ "Bands",
+ "Frequency bands used by the modem",
+ G_VARIANT_TYPE ("au"),
+ NULL,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_BANDS, properties[PROP_BANDS]);
+
+ properties[PROP_ACCESS_TECHNOLOGIES] =
+ g_param_spec_flags (MM_SIMPLE_PROPERTY_ACCESS_TECHNOLOGIES,
+ "Access Technologies",
+ "Access technologies used by the modem",
+ MM_TYPE_MODEM_ACCESS_TECHNOLOGY,
+ MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_ACCESS_TECHNOLOGIES, properties[PROP_ACCESS_TECHNOLOGIES]);
+
+ properties[PROP_3GPP_REGISTRATION_STATE] =
+ g_param_spec_enum (MM_SIMPLE_PROPERTY_3GPP_REGISTRATION_STATE,
+ "3GPP registration state",
+ "Registration state in the 3GPP network",
+ MM_TYPE_MODEM_3GPP_REGISTRATION_STATE,
+ MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_3GPP_REGISTRATION_STATE, properties[PROP_3GPP_REGISTRATION_STATE]);
+
+ properties[PROP_3GPP_OPERATOR_CODE] =
+ g_param_spec_string (MM_SIMPLE_PROPERTY_3GPP_OPERATOR_CODE,
+ "3GPP operator code",
+ "Code of the current operator in the 3GPP network",
+ NULL,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_3GPP_OPERATOR_CODE, properties[PROP_3GPP_OPERATOR_CODE]);
+
+ properties[PROP_3GPP_OPERATOR_NAME] =
+ g_param_spec_string (MM_SIMPLE_PROPERTY_3GPP_OPERATOR_NAME,
+ "3GPP operator name",
+ "Name of the current operator in the 3GPP network",
+ NULL,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_3GPP_OPERATOR_NAME, properties[PROP_3GPP_OPERATOR_NAME]);
+
+ properties[PROP_CDMA_CDMA1X_REGISTRATION_STATE] =
+ g_param_spec_enum (MM_SIMPLE_PROPERTY_CDMA_CDMA1X_REGISTRATION_STATE,
+ "CDMA1x registration state",
+ "Registration state in the CDMA1x network",
+ MM_TYPE_MODEM_CDMA_REGISTRATION_STATE,
+ MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_CDMA_CDMA1X_REGISTRATION_STATE, properties[PROP_CDMA_CDMA1X_REGISTRATION_STATE]);
+
+ properties[PROP_CDMA_EVDO_REGISTRATION_STATE] =
+ g_param_spec_enum (MM_SIMPLE_PROPERTY_CDMA_EVDO_REGISTRATION_STATE,
+ "EV-DO registration state",
+ "Registration state in the EV-DO network",
+ MM_TYPE_MODEM_CDMA_REGISTRATION_STATE,
+ MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_CDMA_EVDO_REGISTRATION_STATE, properties[PROP_CDMA_EVDO_REGISTRATION_STATE]);
+
+ properties[PROP_CDMA_SID] =
+ g_param_spec_uint (MM_SIMPLE_PROPERTY_CDMA_SID,
+ "CDMA1x SID",
+ "System Identifier of the serving CDMA1x network",
+ 0,
+ SID_UNKNOWN,
+ SID_UNKNOWN,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_CDMA_SID, properties[PROP_CDMA_SID]);
+
+ properties[PROP_CDMA_NID] =
+ g_param_spec_uint (MM_SIMPLE_PROPERTY_CDMA_NID,
+ "CDMA1x NID",
+ "Network Identifier of the serving CDMA1x network",
+ 0,
+ NID_UNKNOWN,
+ NID_UNKNOWN,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_CDMA_NID, properties[PROP_CDMA_NID]);
+}
diff --git a/libmm-glib/mm-simple-status.h b/libmm-glib/mm-simple-status.h
new file mode 100644
index 00000000..884b6b95
--- /dev/null
+++ b/libmm-glib/mm-simple-status.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2011 Google, Inc.
+ */
+
+#ifndef MM_SIMPLE_STATUS_H
+#define MM_SIMPLE_STATUS_H
+
+#include <ModemManager.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MM_TYPE_SIMPLE_STATUS (mm_simple_status_get_type ())
+#define MM_SIMPLE_STATUS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SIMPLE_STATUS, MMSimpleStatus))
+#define MM_SIMPLE_STATUS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SIMPLE_STATUS, MMSimpleStatusClass))
+#define MM_IS_SIMPLE_STATUS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SIMPLE_STATUS))
+#define MM_IS_SIMPLE_STATUS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SIMPLE_STATUS))
+#define MM_SIMPLE_STATUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SIMPLE_STATUS, MMSimpleStatusClass))
+
+#define MM_SIMPLE_PROPERTY_STATE "state"
+#define MM_SIMPLE_PROPERTY_SIGNAL_QUALITY "signal-quality"
+#define MM_SIMPLE_PROPERTY_BANDS "bands"
+#define MM_SIMPLE_PROPERTY_ACCESS_TECHNOLOGIES "access-technologies"
+
+#define MM_SIMPLE_PROPERTY_3GPP_REGISTRATION_STATE "m3gpp-registration-state"
+#define MM_SIMPLE_PROPERTY_3GPP_OPERATOR_CODE "m3gpp-operator-code"
+#define MM_SIMPLE_PROPERTY_3GPP_OPERATOR_NAME "m3gpp-operator-name"
+
+#define MM_SIMPLE_PROPERTY_CDMA_CDMA1X_REGISTRATION_STATE "cdma-cdma1x-registration-state"
+#define MM_SIMPLE_PROPERTY_CDMA_EVDO_REGISTRATION_STATE "cdma-evdo-registration-state"
+#define MM_SIMPLE_PROPERTY_CDMA_SID "cdma-sid"
+#define MM_SIMPLE_PROPERTY_CDMA_NID "cdma-nid"
+
+typedef struct _MMSimpleStatus MMSimpleStatus;
+typedef struct _MMSimpleStatusClass MMSimpleStatusClass;
+typedef struct _MMSimpleStatusPrivate MMSimpleStatusPrivate;
+
+struct _MMSimpleStatus {
+ GObject parent;
+ MMSimpleStatusPrivate *priv;
+};
+
+struct _MMSimpleStatusClass {
+ GObjectClass parent;
+};
+
+GType mm_simple_status_get_type (void);
+
+MMSimpleStatus *mm_simple_status_new (void);
+MMSimpleStatus *mm_simple_status_new_from_dictionary (GVariant *dictionary,
+ GError **error);
+
+MMModemState mm_simple_status_get_state (MMSimpleStatus *self);
+guint32 mm_simple_status_get_signal_quality (MMSimpleStatus *self,
+ gboolean *recent);
+void mm_simple_status_get_bands (MMSimpleStatus *self,
+ const MMModemBand **bands,
+ guint *n_bands);
+MMModemAccessTechnology mm_simple_status_get_access_technologies (MMSimpleStatus *self);
+
+MMModem3gppRegistrationState mm_simple_status_get_3gpp_registration_state (MMSimpleStatus *self);
+const gchar *mm_simple_status_get_3gpp_operator_code (MMSimpleStatus *self);
+const gchar *mm_simple_status_get_3gpp_operator_name (MMSimpleStatus *self);
+
+MMModemCdmaRegistrationState mm_simple_status_get_cdma_cdma1x_registration_state (MMSimpleStatus *self);
+MMModemCdmaRegistrationState mm_simple_status_get_cdma_evdo_registration_state (MMSimpleStatus *self);
+guint mm_simple_status_get_cdma_sid (MMSimpleStatus *self);
+guint mm_simple_status_get_cdma_nid (MMSimpleStatus *self);
+
+GVariant *mm_simple_status_get_dictionary (MMSimpleStatus *self);
+
+G_END_DECLS
+
+#endif /* MM_SIMPLE_STATUS_H */
diff --git a/libmm-glib/mm-sms-properties.c b/libmm-glib/mm-sms-properties.c
new file mode 100644
index 00000000..3d619220
--- /dev/null
+++ b/libmm-glib/mm-sms-properties.c
@@ -0,0 +1,586 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2011 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "mm-errors-types.h"
+#include "mm-common-helpers.h"
+#include "mm-sms-properties.h"
+
+G_DEFINE_TYPE (MMSmsProperties, mm_sms_properties, G_TYPE_OBJECT);
+
+#define PROPERTY_TEXT "text"
+#define PROPERTY_DATA "data"
+#define PROPERTY_NUMBER "number"
+#define PROPERTY_SMSC "smsc"
+#define PROPERTY_VALIDITY "validity"
+#define PROPERTY_CLASS "class"
+#define PROPERTY_DELIVERY_REPORT_REQUEST "delivery-report-request"
+
+struct _MMSmsPropertiesPrivate {
+ gchar *text;
+ GByteArray *data;
+ gchar *number;
+ gchar *smsc;
+ gboolean validity_set;
+ guint validity;
+ gboolean class_set;
+ guint class;
+ gboolean delivery_report_request_set;
+ gboolean delivery_report_request;
+};
+
+/*****************************************************************************/
+
+void
+mm_sms_properties_set_text (MMSmsProperties *self,
+ const gchar *text)
+{
+ g_return_if_fail (MM_IS_SMS_PROPERTIES (self));
+
+ g_free (self->priv->text);
+ self->priv->text = g_strdup (text);
+}
+
+void
+mm_sms_properties_set_data (MMSmsProperties *self,
+ const guint8 *data,
+ gsize data_length)
+{
+ g_return_if_fail (MM_IS_SMS_PROPERTIES (self));
+
+ if (self->priv->data)
+ g_byte_array_unref (self->priv->data);
+
+ if (data && data_length)
+ self->priv->data = g_byte_array_append (g_byte_array_sized_new (data_length),
+ data,
+ data_length);
+ else
+ self->priv->data = NULL;
+}
+
+void
+mm_sms_properties_set_data_bytearray (MMSmsProperties *self,
+ GByteArray *data)
+{
+ g_return_if_fail (MM_IS_SMS_PROPERTIES (self));
+
+ if (self->priv->data)
+ g_byte_array_unref (self->priv->data);
+
+ self->priv->data = (data ? g_byte_array_ref (data) : NULL);
+}
+
+void
+mm_sms_properties_set_number (MMSmsProperties *self,
+ const gchar *number)
+{
+ g_return_if_fail (MM_IS_SMS_PROPERTIES (self));
+
+ g_free (self->priv->number);
+ self->priv->number = g_strdup (number);
+}
+
+void
+mm_sms_properties_set_smsc (MMSmsProperties *self,
+ const gchar *smsc)
+{
+ g_return_if_fail (MM_IS_SMS_PROPERTIES (self));
+
+ g_free (self->priv->smsc);
+ self->priv->smsc = g_strdup (smsc);
+}
+
+void
+mm_sms_properties_set_validity (MMSmsProperties *self,
+ guint validity)
+{
+ g_return_if_fail (MM_IS_SMS_PROPERTIES (self));
+
+ self->priv->validity_set = TRUE;
+ self->priv->validity = validity;
+}
+
+void
+mm_sms_properties_set_class (MMSmsProperties *self,
+ guint class)
+{
+ g_return_if_fail (MM_IS_SMS_PROPERTIES (self));
+
+ self->priv->class_set = TRUE;
+ self->priv->class = class;
+}
+
+void
+mm_sms_properties_set_delivery_report_request (MMSmsProperties *self,
+ gboolean request)
+{
+ g_return_if_fail (MM_IS_SMS_PROPERTIES (self));
+
+ self->priv->delivery_report_request_set = TRUE;
+ self->priv->delivery_report_request = request;
+}
+
+/*****************************************************************************/
+
+const gchar *
+mm_sms_properties_get_text (MMSmsProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SMS_PROPERTIES (self), NULL);
+
+ return self->priv->text;
+}
+
+const gchar *
+mm_sms_properties_get_number (MMSmsProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SMS_PROPERTIES (self), NULL);
+
+ return self->priv->number;
+}
+
+const guint8 *
+mm_sms_properties_get_data (MMSmsProperties *self,
+ gsize *data_len)
+{
+ g_return_val_if_fail (MM_IS_SMS_PROPERTIES (self), NULL);
+
+ if (self->priv->data && data_len)
+ *data_len = self->priv->data->len;
+
+ return self->priv->data->data;
+}
+
+GByteArray *
+mm_sms_properties_peek_data_bytearray (MMSmsProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SMS_PROPERTIES (self), NULL);
+
+ return self->priv->data;
+}
+
+GByteArray *
+mm_sms_properties_get_data_bytearray (MMSmsProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SMS_PROPERTIES (self), NULL);
+
+ return (self->priv->data ? g_byte_array_ref (self->priv->data) : NULL);
+}
+
+const gchar *
+mm_sms_properties_get_smsc (MMSmsProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SMS_PROPERTIES (self), NULL);
+
+ return self->priv->smsc;
+}
+
+guint
+mm_sms_properties_get_validity (MMSmsProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SMS_PROPERTIES (self), 0);
+
+ return self->priv->validity;
+}
+
+guint
+mm_sms_properties_get_class (MMSmsProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SMS_PROPERTIES (self), 0);
+
+ return self->priv->class;
+}
+
+gboolean
+mm_sms_properties_get_delivery_report_request (MMSmsProperties *self)
+{
+ g_return_val_if_fail (MM_IS_SMS_PROPERTIES (self), FALSE);
+
+ return self->priv->delivery_report_request;
+}
+
+/*****************************************************************************/
+
+GVariant *
+mm_sms_properties_get_dictionary (MMSmsProperties *self)
+{
+ GVariantBuilder builder;
+
+ /* We do allow NULL */
+ if (!self)
+ return NULL;
+
+ g_return_val_if_fail (MM_IS_SMS_PROPERTIES (self), NULL);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+ if (self->priv->text)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_TEXT,
+ g_variant_new_string (self->priv->text));
+
+ if (self->priv->data)
+ g_variant_builder_add (
+ &builder,
+ "{sv}",
+ PROPERTY_DATA,
+ g_variant_new_from_data (G_VARIANT_TYPE ("ay"),
+ self->priv->data->data,
+ self->priv->data->len * sizeof (guint8),
+ TRUE,
+ NULL,
+ NULL));
+
+ if (self->priv->number)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_NUMBER,
+ g_variant_new_string (self->priv->number));
+
+ if (self->priv->smsc)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_SMSC,
+ g_variant_new_string (self->priv->smsc));
+
+ if (self->priv->validity_set)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_VALIDITY,
+ g_variant_new_uint32 (self->priv->validity));
+
+ if (self->priv->class_set)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_CLASS,
+ g_variant_new_uint32 (self->priv->class));
+
+ if (self->priv->delivery_report_request_set)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_DELIVERY_REPORT_REQUEST,
+ g_variant_new_boolean (self->priv->delivery_report_request));
+
+ return g_variant_ref_sink (g_variant_builder_end (&builder));
+}
+
+/*****************************************************************************/
+
+static guint
+parse_uint (const gchar *str,
+ GError **error)
+{
+ guint num;
+
+ errno = 0;
+ num = strtoul (str, NULL, 10);
+ if ((num < G_MAXUINT32) && (errno == 0))
+ return num;
+
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid properties string, cannot parse '%s' as uint",
+ str);
+ return 0;
+}
+
+static gboolean
+parse_boolean (const gchar *str,
+ GError **error)
+{
+ if (g_ascii_strcasecmp (str, "yes") == 0 ||
+ g_ascii_strcasecmp (str, "true") == 0 ||
+ g_str_equal (str, "1"))
+ return TRUE;
+
+ if (g_ascii_strcasecmp (str, "no") == 0 ||
+ g_ascii_strcasecmp (str, "false") == 0 ||
+ g_str_equal (str, "0"))
+ return FALSE;
+
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid properties string, cannot parse '%s' as boolean",
+ str);
+ return FALSE;
+}
+
+static gboolean
+consume_string (MMSmsProperties *self,
+ const gchar *key,
+ const gchar *value,
+ GError **error)
+{
+ if (g_str_equal (key, PROPERTY_TEXT))
+ mm_sms_properties_set_text (self, value);
+ else if (g_str_equal (key, PROPERTY_NUMBER))
+ mm_sms_properties_set_number (self, value);
+ else if (g_str_equal (key, PROPERTY_SMSC))
+ mm_sms_properties_set_smsc (self, value);
+ else if (g_str_equal (key, PROPERTY_VALIDITY)) {
+ GError *inner_error = NULL;
+ guint n;
+
+ n = parse_uint (value, &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ mm_sms_properties_set_validity (self, n);
+ } else if (g_str_equal (key, PROPERTY_CLASS)) {
+ GError *inner_error = NULL;
+ guint n;
+
+ n = parse_uint (value, &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ mm_sms_properties_set_class (self, n);
+ } else if (g_str_equal (key, PROPERTY_DELIVERY_REPORT_REQUEST)) {
+ GError *inner_error = NULL;
+ gboolean request;
+
+ request = parse_boolean (value, &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ mm_sms_properties_set_delivery_report_request (self, request);
+ } else if (g_str_equal (key, PROPERTY_DATA)) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid properties string, key '%s' cannot be given in a string",
+ key);
+ return FALSE;
+ } else {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid properties string, unexpected key '%s'",
+ key);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+typedef struct {
+ MMSmsProperties *properties;
+ GError *error;
+} ParseKeyValueContext;
+
+static gboolean
+key_value_foreach (const gchar *key,
+ const gchar *value,
+ ParseKeyValueContext *ctx)
+{
+ return consume_string (ctx->properties,
+ key,
+ value,
+ &ctx->error);
+}
+
+MMSmsProperties *
+mm_sms_properties_new_from_string (const gchar *str,
+ GError **error)
+{
+ ParseKeyValueContext ctx;
+
+ ctx.properties = mm_sms_properties_new ();
+ ctx.error = NULL;
+
+ mm_common_parse_key_value_string (str,
+ &ctx.error,
+ (MMParseKeyValueForeachFn)key_value_foreach,
+ &ctx);
+
+ /* If error, destroy the object */
+ if (ctx.error) {
+ g_propagate_error (error, ctx.error);
+ g_object_unref (ctx.properties);
+ ctx.properties = NULL;
+ }
+
+ return ctx.properties;
+}
+
+/*****************************************************************************/
+
+static gboolean
+consume_variant (MMSmsProperties *properties,
+ const gchar *key,
+ GVariant *value,
+ GError **error)
+{
+ if (g_str_equal (key, PROPERTY_TEXT))
+ mm_sms_properties_set_text (
+ properties,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_DATA)) {
+ const guint8 *data;
+ gsize data_len = 0;
+
+ data = g_variant_get_fixed_array (value, &data_len, sizeof (guint8));
+ mm_sms_properties_set_data (
+ properties,
+ data,
+ data_len);
+ } else if (g_str_equal (key, PROPERTY_NUMBER))
+ mm_sms_properties_set_number (
+ properties,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_SMSC))
+ mm_sms_properties_set_smsc (
+ properties,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_VALIDITY))
+ mm_sms_properties_set_validity (
+ properties,
+ g_variant_get_uint32 (value));
+ else if (g_str_equal (key, PROPERTY_CLASS))
+ mm_sms_properties_set_class (
+ properties,
+ g_variant_get_uint32 (value));
+ else if (g_str_equal (key, PROPERTY_DELIVERY_REPORT_REQUEST))
+ mm_sms_properties_set_delivery_report_request (
+ properties,
+ g_variant_get_boolean (value));
+ else {
+ /* Set error */
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid properties dictionary, unexpected key '%s'",
+ key);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+MMSmsProperties *
+mm_sms_properties_new_from_dictionary (GVariant *dictionary,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ GVariantIter iter;
+ gchar *key;
+ GVariant *value;
+ MMSmsProperties *properties;
+
+ properties = mm_sms_properties_new ();
+ if (!dictionary)
+ return properties;
+
+ if (!g_variant_is_of_type (dictionary, G_VARIANT_TYPE ("a{sv}"))) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create SMS properties from dictionary: "
+ "invalid variant type received");
+ g_object_unref (properties);
+ return NULL;
+ }
+
+ g_variant_iter_init (&iter, dictionary);
+ while (!inner_error &&
+ g_variant_iter_next (&iter, "{sv}", &key, &value)) {
+ consume_variant (properties,
+ key,
+ value,
+ &inner_error);
+ g_free (key);
+ g_variant_unref (value);
+ }
+
+ /* If error, destroy the object */
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ g_object_unref (properties);
+ properties = NULL;
+ }
+
+ return properties;
+}
+
+/*****************************************************************************/
+
+MMSmsProperties *
+mm_sms_properties_dup (MMSmsProperties *orig)
+{
+ GVariant *dict;
+ MMSmsProperties *copy;
+ GError *error = NULL;
+
+ g_return_val_if_fail (MM_IS_SMS_PROPERTIES (orig), NULL);
+
+ dict = mm_sms_properties_get_dictionary (orig);
+ copy = mm_sms_properties_new_from_dictionary (dict, &error);
+ g_assert_no_error (error);
+ g_variant_unref (dict);
+
+ return copy;
+}
+
+/*****************************************************************************/
+
+MMSmsProperties *
+mm_sms_properties_new (void)
+{
+ return (MM_SMS_PROPERTIES (g_object_new (MM_TYPE_SMS_PROPERTIES, NULL)));
+}
+
+static void
+mm_sms_properties_init (MMSmsProperties *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
+ MM_TYPE_SMS_PROPERTIES,
+ MMSmsPropertiesPrivate);
+}
+
+static void
+finalize (GObject *object)
+{
+ MMSmsProperties *self = MM_SMS_PROPERTIES (object);
+
+ g_free (self->priv->text);
+ g_free (self->priv->number);
+ g_free (self->priv->smsc);
+ if (self->priv->data)
+ g_byte_array_unref (self->priv->data);
+
+ G_OBJECT_CLASS (mm_sms_properties_parent_class)->finalize (object);
+}
+
+static void
+mm_sms_properties_class_init (MMSmsPropertiesClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMSmsPropertiesPrivate));
+
+ object_class->finalize = finalize;
+}
diff --git a/libmm-glib/mm-sms-properties.h b/libmm-glib/mm-sms-properties.h
new file mode 100644
index 00000000..dc944162
--- /dev/null
+++ b/libmm-glib/mm-sms-properties.h
@@ -0,0 +1,87 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Google, Inc.
+ */
+
+#ifndef MM_SMS_PROPERTIES_H
+#define MM_SMS_PROPERTIES_H
+
+#include <ModemManager.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MM_TYPE_SMS_PROPERTIES (mm_sms_properties_get_type ())
+#define MM_SMS_PROPERTIES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SMS_PROPERTIES, MMSmsProperties))
+#define MM_SMS_PROPERTIES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SMS_PROPERTIES, MMSmsPropertiesClass))
+#define MM_IS_SMS_PROPERTIES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SMS_PROPERTIES))
+#define MM_IS_SMS_PROPERTIES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SMS_PROPERTIES))
+#define MM_SMS_PROPERTIES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SMS_PROPERTIES, MMSmsPropertiesClass))
+
+typedef struct _MMSmsProperties MMSmsProperties;
+typedef struct _MMSmsPropertiesClass MMSmsPropertiesClass;
+typedef struct _MMSmsPropertiesPrivate MMSmsPropertiesPrivate;
+
+struct _MMSmsProperties {
+ GObject parent;
+ MMSmsPropertiesPrivate *priv;
+};
+
+struct _MMSmsPropertiesClass {
+ GObjectClass parent;
+};
+
+GType mm_sms_properties_get_type (void);
+
+MMSmsProperties *mm_sms_properties_new (void);
+MMSmsProperties *mm_sms_properties_new_from_string (const gchar *str,
+ GError **error);
+MMSmsProperties *mm_sms_properties_new_from_dictionary (GVariant *dictionary,
+ GError **error);
+
+MMSmsProperties *mm_sms_properties_dup (MMSmsProperties *orig);
+
+void mm_sms_properties_set_text (MMSmsProperties *self,
+ const gchar *text);
+void mm_sms_properties_set_data (MMSmsProperties *self,
+ const guint8 *data,
+ gsize data_length);
+void mm_sms_properties_set_data_bytearray (MMSmsProperties *self,
+ GByteArray *data);
+void mm_sms_properties_set_number (MMSmsProperties *self,
+ const gchar *number);
+void mm_sms_properties_set_smsc (MMSmsProperties *self,
+ const gchar *smsc);
+void mm_sms_properties_set_validity (MMSmsProperties *self,
+ guint validity);
+void mm_sms_properties_set_class (MMSmsProperties *self,
+ guint class);
+void mm_sms_properties_set_delivery_report_request (MMSmsProperties *self,
+ gboolean request);
+
+const gchar *mm_sms_properties_get_text (MMSmsProperties *self);
+const guint8 *mm_sms_properties_get_data (MMSmsProperties *self,
+ gsize *data_len);
+GByteArray *mm_sms_properties_peek_data_bytearray (MMSmsProperties *self);
+GByteArray *mm_sms_properties_get_data_bytearray (MMSmsProperties *self);
+const gchar *mm_sms_properties_get_number (MMSmsProperties *self);
+const gchar *mm_sms_properties_get_smsc (MMSmsProperties *self);
+guint mm_sms_properties_get_validity (MMSmsProperties *self);
+guint mm_sms_properties_get_class (MMSmsProperties *self);
+gboolean mm_sms_properties_get_delivery_report_request (MMSmsProperties *self);
+
+GVariant *mm_sms_properties_get_dictionary (MMSmsProperties *self);
+
+G_END_DECLS
+
+#endif /* MM_SMS_PROPERTIES_H */
diff --git a/libmm-glib/mm-unlock-retries.c b/libmm-glib/mm-unlock-retries.c
new file mode 100644
index 00000000..a329c411
--- /dev/null
+++ b/libmm-glib/mm-unlock-retries.c
@@ -0,0 +1,218 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Google, Inc.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "mm-enums-types.h"
+#include "mm-unlock-retries.h"
+
+G_DEFINE_TYPE (MMUnlockRetries, mm_unlock_retries, G_TYPE_OBJECT);
+
+struct _MMUnlockRetriesPrivate {
+ GHashTable *ht;
+};
+
+/*****************************************************************************/
+
+void
+mm_unlock_retries_set (MMUnlockRetries *self,
+ MMModemLock lock,
+ guint retries)
+{
+ g_hash_table_replace (self->priv->ht,
+ GUINT_TO_POINTER (lock),
+ GUINT_TO_POINTER (retries));
+}
+
+void
+mm_unlock_retries_unset (MMUnlockRetries *self,
+ MMModemLock lock)
+{
+ g_hash_table_remove (self->priv->ht,
+ GUINT_TO_POINTER (lock));
+}
+
+guint
+mm_unlock_retries_get (MMUnlockRetries *self,
+ MMModemLock lock)
+{
+ gpointer value = NULL;
+
+ return (g_hash_table_lookup_extended (self->priv->ht,
+ GUINT_TO_POINTER (lock),
+ NULL, /* original key not needed */
+ &value) ?
+ GPOINTER_TO_UINT (value) :
+ MM_UNLOCK_RETRIES_UNKNOWN);
+}
+
+/*****************************************************************************/
+
+gboolean
+mm_unlock_retries_cmp (MMUnlockRetries *a,
+ MMUnlockRetries *b)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ if (g_hash_table_size (a->priv->ht) != g_hash_table_size (b->priv->ht))
+ return FALSE;
+
+ g_hash_table_iter_init (&iter, a->priv->ht);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ g_assert (GPOINTER_TO_UINT (value) != MM_UNLOCK_RETRIES_UNKNOWN);
+
+ if (GPOINTER_TO_UINT (value) != mm_unlock_retries_get (b, GPOINTER_TO_UINT (key)))
+ return FALSE;
+ }
+
+ /* All equal! */
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+void
+mm_unlock_retries_foreach (MMUnlockRetries *self,
+ MMUnlockRetriesForeachCb callback,
+ gpointer user_data)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, self->priv->ht);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ callback (GPOINTER_TO_UINT (key),
+ GPOINTER_TO_UINT (value),
+ user_data);
+ }
+}
+
+/*****************************************************************************/
+
+GVariant *
+mm_unlock_retries_get_dictionary (MMUnlockRetries *self)
+{
+ GVariantBuilder builder;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ /* We do allow NULL */
+ if (!self)
+ return NULL;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{uu}"));
+
+ g_hash_table_iter_init (&iter, self->priv->ht);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ g_variant_builder_add (&builder,
+ "{uu}",
+ GPOINTER_TO_UINT (key),
+ GPOINTER_TO_UINT (value));
+ }
+
+ return g_variant_ref_sink (g_variant_builder_end (&builder));
+}
+
+/*****************************************************************************/
+
+MMUnlockRetries *
+mm_unlock_retries_new_from_dictionary (GVariant *dictionary)
+{
+ GVariantIter iter;
+ guint key, value;
+ MMUnlockRetries *self;
+
+ self = mm_unlock_retries_new ();
+ if (!dictionary)
+ return self;
+
+ g_variant_iter_init (&iter, dictionary);
+ while (g_variant_iter_next (&iter, "{uu}", &key, &value)) {
+ mm_unlock_retries_set (self,
+ (MMModemLock)key,
+ value);
+ }
+
+ return self;
+}
+
+/*****************************************************************************/
+
+gchar *
+mm_unlock_retries_build_string (MMUnlockRetries *self)
+{
+ GString *str = NULL;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, self->priv->ht);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ const gchar *lock_name;
+ guint retries;
+
+ lock_name = mm_modem_lock_get_string ((MMModemLock)GPOINTER_TO_UINT (key));
+ retries = GPOINTER_TO_UINT (value);
+
+ if (!str) {
+ str = g_string_new ("");
+ g_string_append_printf (str, "%s (%u)", lock_name, retries);
+ } else
+ g_string_append_printf (str, ", %s (%u)", lock_name, retries);
+ }
+
+ return (str ? g_string_free (str, FALSE) : NULL);
+}
+
+/*****************************************************************************/
+
+MMUnlockRetries *
+mm_unlock_retries_new (void)
+{
+ return (MM_UNLOCK_RETRIES (
+ g_object_new (MM_TYPE_UNLOCK_RETRIES, NULL)));
+}
+
+static void
+mm_unlock_retries_init (MMUnlockRetries *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
+ MM_TYPE_UNLOCK_RETRIES,
+ MMUnlockRetriesPrivate);
+ self->priv->ht = g_hash_table_new (g_direct_hash,
+ g_direct_equal);
+}
+
+static void
+finalize (GObject *object)
+{
+ MMUnlockRetries *self = MM_UNLOCK_RETRIES (object);
+
+ g_hash_table_destroy (self->priv->ht);
+
+ G_OBJECT_CLASS (mm_unlock_retries_parent_class)->finalize (object);
+}
+
+static void
+mm_unlock_retries_class_init (MMUnlockRetriesClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMUnlockRetriesPrivate));
+
+ object_class->finalize = finalize;
+}
diff --git a/libmm-glib/mm-unlock-retries.h b/libmm-glib/mm-unlock-retries.h
new file mode 100644
index 00000000..48851b21
--- /dev/null
+++ b/libmm-glib/mm-unlock-retries.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Google, Inc.
+ */
+
+#ifndef MM_UNLOCK_RETRIES_H
+#define MM_UNLOCK_RETRIES_H
+
+#include <ModemManager.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MM_TYPE_UNLOCK_RETRIES (mm_unlock_retries_get_type ())
+#define MM_UNLOCK_RETRIES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_UNLOCK_RETRIES, MMUnlockRetries))
+#define MM_UNLOCK_RETRIES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_UNLOCK_RETRIES, MMUnlockRetriesClass))
+#define MM_IS_UNLOCK_RETRIES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_UNLOCK_RETRIES))
+#define MM_IS_UNLOCK_RETRIES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_UNLOCK_RETRIES))
+#define MM_UNLOCK_RETRIES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_UNLOCK_RETRIES, MMUnlockRetriesClass))
+
+#define MM_UNLOCK_RETRIES_UNKNOWN 999
+
+typedef struct _MMUnlockRetries MMUnlockRetries;
+typedef struct _MMUnlockRetriesClass MMUnlockRetriesClass;
+typedef struct _MMUnlockRetriesPrivate MMUnlockRetriesPrivate;
+
+struct _MMUnlockRetries {
+ GObject parent;
+ MMUnlockRetriesPrivate *priv;
+};
+
+struct _MMUnlockRetriesClass {
+ GObjectClass parent;
+};
+
+GType mm_unlock_retries_get_type (void);
+
+MMUnlockRetries *mm_unlock_retries_new (void);
+MMUnlockRetries *mm_unlock_retries_new_from_dictionary (GVariant *dictionary);
+
+void mm_unlock_retries_set (MMUnlockRetries *self,
+ MMModemLock lock,
+ guint retries);
+
+void mm_unlock_retries_unset (MMUnlockRetries *self,
+ MMModemLock lock);
+
+guint mm_unlock_retries_get (MMUnlockRetries *self,
+ MMModemLock lock);
+
+typedef void (* MMUnlockRetriesForeachCb) (MMModemLock lock,
+ guint count,
+ gpointer user_data);
+
+void mm_unlock_retries_foreach (MMUnlockRetries *self,
+ MMUnlockRetriesForeachCb callback,
+ gpointer user_data);
+
+gboolean mm_unlock_retries_cmp (MMUnlockRetries *a,
+ MMUnlockRetries *b);
+
+GVariant *mm_unlock_retries_get_dictionary (MMUnlockRetries *self);
+
+gchar *mm_unlock_retries_build_string (MMUnlockRetries *self);
+
+G_END_DECLS
+
+#endif /* MM_UNLOCK_RETRIES_H */
diff --git a/libmm-glib/tests/Makefile.am b/libmm-glib/tests/Makefile.am
new file mode 100644
index 00000000..2f6da036
--- /dev/null
+++ b/libmm-glib/tests/Makefile.am
@@ -0,0 +1,27 @@
+
+noinst_PROGRAMS = \
+ test-common-helpers
+
+test_common_helpers_SOURCES = \
+ test-common-helpers.c
+
+test_common_helpers_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/include \
+ -I$(top_builddir)/include \
+ -I$(top_srcdir)/libmm-glib \
+ -I$(top_builddir)/libmm-glib \
+ -I${top_srcdir}/libmm-glib/generated \
+ -I${top_builddir}/libmm-glib/generated
+
+test_common_helpers_LDADD = \
+ $(top_builddir)/libmm-glib/libmm-glib.la \
+ $(MM_LIBS)
+
+if WITH_TESTS
+
+check-local: test-common-helpers
+ $(abs_builddir)/test-common-helpers
+
+endif
diff --git a/libmm-glib/tests/test-common-helpers.c b/libmm-glib/tests/test-common-helpers.c
new file mode 100644
index 00000000..a54fe2d8
--- /dev/null
+++ b/libmm-glib/tests/test-common-helpers.c
@@ -0,0 +1,529 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Google, Inc.
+ */
+
+#include <glib.h>
+
+#include <libmm-common.h>
+
+/********************* KEY VALUE PARSER TESTS *********************/
+
+typedef struct {
+ const gchar *key;
+ const gchar *value;
+} KeyValueEntry;
+
+/* ---- Expected cases ---- */
+
+typedef struct {
+ const KeyValueEntry *entries;
+ guint n_entries;
+ guint i;
+} CommonKeyValueTestContext;
+
+static gboolean
+common_key_value_test_foreach (const gchar *key,
+ const gchar *value,
+ CommonKeyValueTestContext *ctx)
+{
+ g_assert_cmpuint (ctx->i, <, ctx->n_entries);
+
+ g_assert_cmpstr (key, ==, ctx->entries[ctx->i].key);
+ g_assert_cmpstr (value, ==, ctx->entries[ctx->i].value);
+ ctx->i++;
+
+ return TRUE;
+}
+
+static void
+common_key_value_test (const gchar *str,
+ const KeyValueEntry *entries,
+ guint n_entries)
+{
+ GError *error = NULL;
+ CommonKeyValueTestContext ctx;
+
+ ctx.entries = entries;
+ ctx.n_entries = n_entries;
+ ctx.i = 0;
+
+ mm_common_parse_key_value_string (str,
+ &error,
+ (MMParseKeyValueForeachFn)common_key_value_test_foreach,
+ &ctx);
+ g_assert_no_error (error);
+ g_assert_cmpuint (ctx.i, ==, ctx.n_entries);
+}
+
+static void
+key_value_test_standard (void)
+{
+ const gchar *str =
+ "key1=value1,"
+ "key2=value2,"
+ "key3=value3";
+ const KeyValueEntry entries[] = {
+ { "key1", "value1" },
+ { "key2", "value2" },
+ { "key3", "value3" }
+ };
+
+ common_key_value_test (str, entries, G_N_ELEMENTS (entries));
+}
+
+static void
+key_value_test_spaces (void)
+{
+ const gchar *str =
+ " key1 = value1 , "
+ "\t\tkey2\t=\tvalue2\t,\t"
+ "\n\nkey3\n=\nvalue3\n";
+ const KeyValueEntry entries[] = {
+ { "key1", "value1" },
+ { "key2", "value2" },
+ { "key3", "value3" }
+ };
+
+ common_key_value_test (str, entries, G_N_ELEMENTS (entries));
+}
+
+static void
+key_value_test_double_quotes (void)
+{
+ const gchar *str =
+ "key1=\"this is a string\","
+ "key2=\"and so is this\"";
+ const KeyValueEntry entries[] = {
+ { "key1", "this is a string" },
+ { "key2", "and so is this" }
+ };
+
+ common_key_value_test (str, entries, G_N_ELEMENTS (entries));
+}
+
+static void
+key_value_test_single_quotes (void)
+{
+ const gchar *str =
+ "key1='this is a string',"
+ "key2='and so is this'";
+ const KeyValueEntry entries[] = {
+ { "key1", "this is a string" },
+ { "key2", "and so is this" }
+ };
+
+ common_key_value_test (str, entries, G_N_ELEMENTS (entries));
+}
+
+static void
+key_value_test_empty_value (void)
+{
+ const gchar *str =
+ "key1=,"
+ "key2=\"\"";
+ const KeyValueEntry entries[] = {
+ { "key1", "" },
+ { "key2", "" }
+ };
+
+ common_key_value_test (str, entries, G_N_ELEMENTS (entries));
+}
+
+static void
+key_value_test_empty_string (void)
+{
+ const gchar *str = "";
+ const KeyValueEntry entries[] = { };
+
+ common_key_value_test (str, entries, G_N_ELEMENTS (entries));
+}
+
+/* ---- Unexpected cases ---- */
+
+static gboolean
+common_key_value_error_test_foreach (const gchar *key,
+ const gchar *value,
+ gpointer none)
+{
+ /* no op */
+ return TRUE;
+}
+
+static void
+common_key_value_error_test (const gchar *str)
+{
+ GError *error = NULL;
+
+ mm_common_parse_key_value_string (str,
+ &error,
+ (MMParseKeyValueForeachFn)common_key_value_error_test_foreach,
+ NULL);
+
+ /* We don't really care about the specific error type */
+ g_assert (error != NULL);
+ g_error_free (error);
+}
+
+static void
+key_value_error_test_no_first_key (void)
+{
+ common_key_value_error_test ("=value1");
+}
+
+static void
+key_value_error_test_no_key (void)
+{
+ common_key_value_error_test ("key1=value1,"
+ "=value2");
+}
+
+static void
+key_value_error_test_missing_double_quotes_0 (void)
+{
+ common_key_value_error_test ("key1=\"value1");
+}
+
+static void
+key_value_error_test_missing_double_quotes_1 (void)
+{
+ common_key_value_error_test ("key1=\"value1,"
+ "key2=\"value2\"");
+}
+
+static void
+key_value_error_test_missing_double_quotes_2 (void)
+{
+ common_key_value_error_test ("key1=\"value1\","
+ "key2=\"value2");
+}
+
+static void
+key_value_error_test_missing_single_quotes_0 (void)
+{
+ common_key_value_error_test ("key1='value1");
+}
+
+static void
+key_value_error_test_missing_single_quotes_1 (void)
+{
+ common_key_value_error_test ("key1='value1,"
+ "key2='value2'");
+}
+
+static void
+key_value_error_test_missing_single_quotes_2 (void)
+{
+ common_key_value_error_test ("key1='value1',"
+ "key2='value2");
+}
+
+static void
+key_value_error_test_missing_comma_0 (void)
+{
+ common_key_value_error_test ("key1=value1 "
+ "key2=value2");
+}
+
+static void
+key_value_error_test_missing_comma_1 (void)
+{
+ common_key_value_error_test ("key1=\"value1\" "
+ "key2=\"value2\"");
+}
+
+static void
+key_value_error_test_missing_comma_2 (void)
+{
+ common_key_value_error_test ("key1='value1' "
+ "key2='value2'");
+}
+
+/********************* BAND ARRAY TESTS *********************/
+
+static void
+common_band_array_cmp_test (gboolean equal,
+ const MMModemBand *bands_a,
+ guint n_bands_a,
+ const MMModemBand *bands_b,
+ guint n_bands_b)
+{
+ GArray *a;
+ GArray *b;
+
+ a = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), n_bands_a);
+ g_array_append_vals (a, bands_a, n_bands_a);
+
+ b = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), n_bands_b);
+ g_array_append_vals (b, bands_b, n_bands_b);
+
+ g_assert_cmpuint (equal, ==, mm_common_bands_garray_cmp (a, b));
+ g_assert_cmpuint (equal, ==, mm_common_bands_garray_cmp (b, a));
+
+ g_array_unref (a);
+ g_array_unref (b);
+}
+
+static void
+band_array_cmp_test_equal_empty (void)
+{
+ const MMModemBand a[] = { };
+ const MMModemBand b[] = { };
+
+ common_band_array_cmp_test (TRUE, a, G_N_ELEMENTS (a), b, G_N_ELEMENTS (b));
+}
+
+static void
+band_array_cmp_test_equal_one (void)
+{
+ const MMModemBand a[] = { MM_MODEM_BAND_EGSM };
+ const MMModemBand b[] = { MM_MODEM_BAND_EGSM };
+
+ common_band_array_cmp_test (TRUE, a, G_N_ELEMENTS (a), b, G_N_ELEMENTS (b));
+}
+
+static void
+band_array_cmp_test_equal_multiple_same_order (void)
+{
+ const MMModemBand a[] = { MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS };
+ const MMModemBand b[] = { MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS };
+
+ common_band_array_cmp_test (TRUE, a, G_N_ELEMENTS (a), b, G_N_ELEMENTS (b));
+}
+
+static void
+band_array_cmp_test_equal_multiple_different_order (void)
+{
+ const MMModemBand a[] = { MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS };
+ const MMModemBand b[] = { MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS, MM_MODEM_BAND_EGSM };
+
+ common_band_array_cmp_test (TRUE, a, G_N_ELEMENTS (a), b, G_N_ELEMENTS (b));
+}
+
+static void
+band_array_cmp_test_different_one (void)
+{
+ const MMModemBand a[] = { MM_MODEM_BAND_EGSM };
+ const MMModemBand b[] = { MM_MODEM_BAND_DCS };
+
+ common_band_array_cmp_test (FALSE, a, G_N_ELEMENTS (a), b, G_N_ELEMENTS (b));
+}
+
+static void
+band_array_cmp_test_different_none (void)
+{
+ const MMModemBand a[] = { };
+ const MMModemBand b[] = { MM_MODEM_BAND_EGSM };
+
+ common_band_array_cmp_test (FALSE, a, G_N_ELEMENTS (a), b, G_N_ELEMENTS (b));
+}
+
+static void
+band_array_cmp_test_different_multiple_1 (void)
+{
+ const MMModemBand a[] = { MM_MODEM_BAND_EGSM };
+ const MMModemBand b[] = { MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS };
+
+ common_band_array_cmp_test (FALSE, a, G_N_ELEMENTS (a), b, G_N_ELEMENTS (b));
+}
+
+static void
+band_array_cmp_test_different_multiple_2 (void)
+{
+ const MMModemBand a[] = { MM_MODEM_BAND_EGSM };
+ const MMModemBand b[] = { MM_MODEM_BAND_DCS, MM_MODEM_BAND_EGSM };
+
+ common_band_array_cmp_test (FALSE, a, G_N_ELEMENTS (a), b, G_N_ELEMENTS (b));
+}
+
+/********************* FIELD PARSERS TESTS *********************/
+
+static void
+field_parser_int (void)
+{
+ gint num;
+ gchar *str;
+
+ /* Failures */
+
+ g_assert (mm_get_int_from_str (NULL, &num) == FALSE);
+
+ g_assert (mm_get_int_from_str ("", &num) == FALSE);
+
+ g_assert (mm_get_int_from_str ("a", &num) == FALSE);
+
+ g_assert (mm_get_int_from_str ("a100", &num) == FALSE);
+
+ g_assert (mm_get_int_from_str ("100a", &num) == FALSE);
+
+ str = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64)G_MAXINT + 1);
+ g_assert (mm_get_int_from_str (str, &num) == FALSE);
+ g_free (str);
+
+ str = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64)(G_MININT) - 1);
+ g_assert (mm_get_int_from_str (str, &num) == FALSE);
+ g_free (str);
+
+ /* Successes */
+
+ g_assert (mm_get_int_from_str ("0", &num) == TRUE);
+ g_assert_cmpint (num, ==, 0);
+
+ g_assert (mm_get_int_from_str ("-100", &num) == TRUE);
+ g_assert_cmpint (num, ==, -100);
+
+ g_assert (mm_get_int_from_str ("100", &num) == TRUE);
+ g_assert_cmpint (num, ==, 100);
+
+ str = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64)G_MAXINT);
+ g_assert (mm_get_int_from_str (str, &num) == TRUE);
+ g_assert_cmpint (num, ==, G_MAXINT);
+ g_free (str);
+
+ str = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64)G_MININT);
+ g_assert (mm_get_int_from_str (str, &num) == TRUE);
+ g_assert_cmpint (num, ==, G_MININT);
+ g_free (str);
+}
+
+static void
+field_parser_uint (void)
+{
+ gchar *str;
+ guint num;
+
+ /* Failures */
+
+ g_assert (mm_get_uint_from_str (NULL, &num) == FALSE);
+
+ g_assert (mm_get_uint_from_str ("", &num) == FALSE);
+
+ g_assert (mm_get_uint_from_str ("a", &num) == FALSE);
+
+ g_assert (mm_get_uint_from_str ("a100", &num) == FALSE);
+
+ g_assert (mm_get_uint_from_str ("100a", &num) == FALSE);
+
+ g_assert (mm_get_uint_from_str ("-100", &num) == FALSE);
+
+ str = g_strdup_printf ("%" G_GUINT64_FORMAT, (guint64)(G_MAXUINT) + 1);
+ g_assert (mm_get_uint_from_str (str, &num) == FALSE);
+ g_free (str);
+
+ /* Successes */
+
+ g_assert (mm_get_uint_from_str ("0", &num) == TRUE);
+ g_assert_cmpuint (num, ==, 0);
+
+ g_assert (mm_get_uint_from_str ("100", &num) == TRUE);
+ g_assert_cmpuint (num, ==, 100);
+
+ str = g_strdup_printf ("%" G_GUINT64_FORMAT, (guint64)G_MAXUINT);
+ g_assert (mm_get_uint_from_str (str, &num) == TRUE);
+ g_assert_cmpuint (num, ==, G_MAXUINT);
+ g_free (str);
+}
+
+static void
+field_parser_double (void)
+{
+ gchar *str;
+ gdouble num;
+
+ /* Failures */
+
+ g_assert (mm_get_double_from_str (NULL, &num) == FALSE);
+
+ g_assert (mm_get_double_from_str ("", &num) == FALSE);
+
+ g_assert (mm_get_double_from_str ("a", &num) == FALSE);
+
+ g_assert (mm_get_double_from_str ("a100", &num) == FALSE);
+
+ g_assert (mm_get_double_from_str ("100a", &num) == FALSE);
+
+ /* Successes */
+
+ g_assert (mm_get_double_from_str ("-100", &num) == TRUE);
+ g_assert (num - (-100.0) < 0000000.1);
+
+ g_assert (mm_get_double_from_str ("-100.7567", &num) == TRUE);
+ g_assert (num - (-100.7567) < 0000000.1);
+
+ g_assert (mm_get_double_from_str ("0", &num) == TRUE);
+ g_assert (num < 0000000.1);
+
+ g_assert (mm_get_double_from_str ("-0.0", &num) == TRUE);
+ g_assert (num < 0000000.1);
+
+ g_assert (mm_get_double_from_str ("0.0", &num) == TRUE);
+ g_assert (num < 0000000.1);
+
+ g_assert (mm_get_double_from_str ("100", &num) == TRUE);
+ g_assert (num - (100.0) < 0000000.1);
+
+ g_assert (mm_get_double_from_str ("100.7567", &num) == TRUE);
+ g_assert (num - (100.7567) < 0000000.1);
+
+ str = g_strdup_printf ("%lf", (gdouble)G_MINDOUBLE);
+ g_assert (mm_get_double_from_str (str, &num) == TRUE);
+ g_assert (num - G_MINDOUBLE < 0000000.1);
+ g_free (str);
+
+ str = g_strdup_printf ("%lf", (gdouble)G_MAXDOUBLE);
+ g_assert (mm_get_double_from_str (str, &num) == TRUE);
+ g_assert (num - G_MAXDOUBLE < 0000000.1);
+ g_free (str);
+}
+
+/**************************************************************/
+
+int main (int argc, char **argv)
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/MM/Common/KeyValue/standard", key_value_test_standard);
+ g_test_add_func ("/MM/Common/KeyValue/spaces", key_value_test_spaces);
+ g_test_add_func ("/MM/Common/KeyValue/double-quotes", key_value_test_double_quotes);
+ g_test_add_func ("/MM/Common/KeyValue/single-quotes", key_value_test_single_quotes);
+ g_test_add_func ("/MM/Common/KeyValue/empty-value", key_value_test_empty_value);
+ g_test_add_func ("/MM/Common/KeyValue/empty-string", key_value_test_empty_string);
+
+ g_test_add_func ("/MM/Common/KeyValue/Error/no-first-key", key_value_error_test_no_first_key);
+ g_test_add_func ("/MM/Common/KeyValue/Error/no-key", key_value_error_test_no_key);
+ g_test_add_func ("/MM/Common/KeyValue/Error/missing-double-quotes-0", key_value_error_test_missing_double_quotes_0);
+ g_test_add_func ("/MM/Common/KeyValue/Error/missing-double-quotes-1", key_value_error_test_missing_double_quotes_1);
+ g_test_add_func ("/MM/Common/KeyValue/Error/missing-double-quotes-2", key_value_error_test_missing_double_quotes_2);
+ g_test_add_func ("/MM/Common/KeyValue/Error/missing-single-quotes-0", key_value_error_test_missing_single_quotes_0);
+ g_test_add_func ("/MM/Common/KeyValue/Error/missing-single-quotes-1", key_value_error_test_missing_single_quotes_1);
+ g_test_add_func ("/MM/Common/KeyValue/Error/missing-single-quotes-2", key_value_error_test_missing_single_quotes_2);
+ g_test_add_func ("/MM/Common/KeyValue/Error/missing-comma-0", key_value_error_test_missing_comma_0);
+ g_test_add_func ("/MM/Common/KeyValue/Error/missing-comma-1", key_value_error_test_missing_comma_1);
+ g_test_add_func ("/MM/Common/KeyValue/Error/missing-comma-2", key_value_error_test_missing_comma_2);
+
+ g_test_add_func ("/MM/Common/BandArray/Cmp/equal-empty", band_array_cmp_test_equal_empty);
+ g_test_add_func ("/MM/Common/BandArray/Cmp/equal-one", band_array_cmp_test_equal_one);
+ g_test_add_func ("/MM/Common/BandArray/Cmp/equal-multiple-same-order", band_array_cmp_test_equal_multiple_same_order);
+ g_test_add_func ("/MM/Common/BandArray/Cmp/equal-multiple-different-order", band_array_cmp_test_equal_multiple_different_order);
+ g_test_add_func ("/MM/Common/BandArray/Cmp/different-one", band_array_cmp_test_different_one);
+ g_test_add_func ("/MM/Common/BandArray/Cmp/different-none", band_array_cmp_test_different_none);
+ g_test_add_func ("/MM/Common/BandArray/Cmp/different-multiple-1", band_array_cmp_test_different_multiple_1);
+ g_test_add_func ("/MM/Common/BandArray/Cmp/different-multiple-2", band_array_cmp_test_different_multiple_2);
+
+ g_test_add_func ("/MM/Common/FieldParsers/Int", field_parser_int);
+ g_test_add_func ("/MM/Common/FieldParsers/Uint", field_parser_uint);
+ g_test_add_func ("/MM/Common/FieldParsers/Double", field_parser_double);
+
+ return g_test_run ();
+}