diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-10-02 15:08:46 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-10-04 10:17:05 +0200 |
commit | b6d628b3a10bf183b918c7afe89a5b260eb87760 (patch) | |
tree | 8d87e92f2d8b7da99e6a0e41e49a6aa0ebbf55bd /libmm-glib | |
parent | 624fdb6ab4544a82774e9805332cc242c1068b0f (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')
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, °rees)) + 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 (); +} |