aboutsummaryrefslogtreecommitdiff
path: root/libmm-glib/mm-common-helpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmm-glib/mm-common-helpers.c')
-rw-r--r--libmm-glib/mm-common-helpers.c1284
1 files changed, 1284 insertions, 0 deletions
diff --git a/libmm-glib/mm-common-helpers.c b/libmm-glib/mm-common-helpers.c
new file mode 100644
index 0000000..838e09f
--- /dev/null
+++ b/libmm-glib/mm-common-helpers.c
@@ -0,0 +1,1284 @@
+/* -*- 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_capabilities_string (const MMModemCapability *capabilities,
+ guint n_capabilities)
+{
+ gboolean first = TRUE;
+ GString *str;
+ guint i;
+
+ if (!capabilities || !n_capabilities)
+ return g_strdup ("none");
+
+ str = g_string_new ("");
+ for (i = 0; i < n_capabilities; i++) {
+ gchar *tmp;
+
+ tmp = mm_modem_capability_build_string_from_mask (capabilities[i]);
+ g_string_append_printf (str, "%s%s",
+ first ? "" : "\n",
+ tmp);
+ g_free (tmp);
+
+ if (first)
+ first = FALSE;
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+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);
+}
+
+gchar *
+mm_common_build_mode_combinations_string (const MMModemModeCombination *modes,
+ guint n_modes)
+{
+ gboolean first = TRUE;
+ GString *str;
+ guint i;
+
+ if (!modes || !n_modes)
+ return g_strdup ("none");
+
+ str = g_string_new ("");
+ for (i = 0; i < n_modes; i++) {
+ gchar *allowed;
+ gchar *preferred;
+
+ allowed = mm_modem_mode_build_string_from_mask (modes[i].allowed);
+ preferred = mm_modem_mode_build_string_from_mask (modes[i].preferred);
+ g_string_append_printf (str, "%sallowed: %s; preferred: %s",
+ first ? "" : "\n",
+ allowed,
+ preferred);
+ g_free (allowed);
+ g_free (preferred);
+
+ 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);
+}
+
+MMModemCapability
+mm_common_get_capabilities_from_string (const gchar *str,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ MMModemCapability capabilities;
+ gchar **capability_strings;
+ GFlagsClass *flags_class;
+
+ capabilities = MM_MODEM_CAPABILITY_NONE;
+
+ flags_class = G_FLAGS_CLASS (g_type_class_ref (MM_TYPE_MODEM_CAPABILITY));
+ capability_strings = g_strsplit (str, "|", -1);
+
+ if (capability_strings) {
+ guint i;
+
+ for (i = 0; capability_strings[i]; i++) {
+ guint j;
+ gboolean found = FALSE;
+
+ for (j = 0; flags_class->values[j].value_nick; j++) {
+ if (!g_ascii_strcasecmp (capability_strings[i], flags_class->values[j].value_nick)) {
+ capabilities |= 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 MMModemCapability value",
+ capability_strings[i]);
+ break;
+ }
+ }
+ }
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ capabilities = MM_MODEM_CAPABILITY_NONE;
+ }
+
+ g_type_class_unref (flags_class);
+ g_strfreev (capability_strings);
+ return capabilities;
+}
+
+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;
+}
+
+GArray *
+mm_common_capability_combinations_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 capability;
+
+ array = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), n);
+ while (g_variant_iter_loop (&iter, "u", &capability))
+ g_array_append_val (array, capability);
+ }
+ }
+
+ /* If nothing set, fallback to default */
+ if (!array) {
+ guint32 capability = MM_MODEM_CAPABILITY_NONE;
+
+ array = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), 1);
+ g_array_append_val (array, capability);
+ }
+
+ return array;
+}
+
+MMModemCapability *
+mm_common_capability_combinations_variant_to_array (GVariant *variant,
+ guint *n_capabilities)
+{
+ GArray *array;
+
+ array = mm_common_capability_combinations_variant_to_garray (variant);
+ if (n_capabilities)
+ *n_capabilities = array->len;
+ return (MMModemCapability *) g_array_free (array, FALSE);
+}
+
+GVariant *
+mm_common_capability_combinations_array_to_variant (const MMModemCapability *capabilities,
+ guint n_capabilities)
+{
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("au"));
+
+ if (n_capabilities > 0) {
+ guint i;
+
+ for (i = 0; i < n_capabilities; i++)
+ g_variant_builder_add_value (&builder,
+ g_variant_new_uint32 ((guint32)capabilities[i]));
+ } else
+ g_variant_builder_add_value (&builder,
+ g_variant_new_uint32 (MM_MODEM_CAPABILITY_NONE));
+
+ return g_variant_builder_end (&builder);
+}
+
+GVariant *
+mm_common_capability_combinations_garray_to_variant (GArray *array)
+{
+ if (array)
+ return mm_common_capability_combinations_array_to_variant ((const MMModemCapability *)array->data,
+ array->len);
+
+ return mm_common_capability_combinations_array_to_variant (NULL, 0);
+}
+
+GVariant *
+mm_common_build_capability_combinations_none (void)
+{
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("au"));
+ g_variant_builder_add_value (&builder,
+ g_variant_new_uint32 (MM_MODEM_CAPABILITY_NONE));
+ return g_variant_builder_end (&builder);
+}
+
+GVariant *
+mm_common_build_capability_combinations_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_CAPABILITY_ANY));
+ return g_variant_builder_end (&builder);
+}
+
+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;
+}
+
+GArray *
+mm_common_mode_combinations_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) {
+ MMModemModeCombination mode;
+
+ array = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), n);
+ while (g_variant_iter_loop (&iter, "(uu)", &mode.allowed, &mode.preferred))
+ g_array_append_val (array, mode);
+ }
+ }
+
+ /* If nothing set, fallback to default */
+ if (!array) {
+ MMModemModeCombination default_mode;
+
+ default_mode.allowed = MM_MODEM_MODE_ANY;
+ default_mode.preferred = MM_MODEM_MODE_NONE;
+ array = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1);
+ g_array_append_val (array, default_mode);
+ }
+
+ return array;
+}
+
+MMModemModeCombination *
+mm_common_mode_combinations_variant_to_array (GVariant *variant,
+ guint *n_modes)
+{
+ GArray *array;
+
+ array = mm_common_mode_combinations_variant_to_garray (variant);
+ if (n_modes)
+ *n_modes = array->len;
+ return (MMModemModeCombination *) g_array_free (array, FALSE);
+}
+
+GVariant *
+mm_common_mode_combinations_array_to_variant (const MMModemModeCombination *modes,
+ guint n_modes)
+{
+ if (n_modes > 0) {
+ GVariantBuilder builder;
+ guint i;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(uu)"));
+
+ for (i = 0; i < n_modes; i++)
+ g_variant_builder_add_value (&builder,
+ g_variant_new ("(uu)",
+ ((guint32)modes[i].allowed),
+ ((guint32)modes[i].preferred)));
+ return g_variant_builder_end (&builder);
+ }
+
+ return mm_common_build_mode_combinations_default ();
+}
+
+GVariant *
+mm_common_mode_combinations_garray_to_variant (GArray *array)
+{
+ if (array)
+ return mm_common_mode_combinations_array_to_variant ((const MMModemModeCombination *)array->data,
+ array->len);
+
+ return mm_common_mode_combinations_array_to_variant (NULL, 0);
+}
+
+GVariant *
+mm_common_build_mode_combinations_default (void)
+{
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(uu)"));
+ g_variant_builder_add_value (&builder,
+ g_variant_new ("(uu)",
+ MM_MODEM_MODE_ANY,
+ MM_MODEM_MODE_NONE));
+ return g_variant_builder_end (&builder);
+}
+
+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)
+{
+ GFlagsClass *flags_class;
+ guint i;
+
+ flags_class = G_FLAGS_CLASS (g_type_class_ref (MM_TYPE_BEARER_IP_FAMILY));
+
+ for (i = 0; flags_class->values[i].value_nick; i++) {
+ if (!g_ascii_strcasecmp (str, flags_class->values[i].value_nick))
+ return flags_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_NONE;
+}
+
+MMBearerAllowedAuth
+mm_common_get_allowed_auth_from_string (const gchar *str,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ MMBearerAllowedAuth allowed_auth;
+ gchar **strings;
+ GFlagsClass *flags_class;
+
+ allowed_auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN;
+
+ flags_class = G_FLAGS_CLASS (g_type_class_ref (MM_TYPE_BEARER_ALLOWED_AUTH));
+ strings = g_strsplit (str, "|", -1);
+
+ if (strings) {
+ guint i;
+
+ for (i = 0; strings[i]; i++) {
+ guint j;
+ gboolean found = FALSE;
+
+ for (j = 0; flags_class->values[j].value_nick; j++) {
+ if (!g_ascii_strcasecmp (strings[i], flags_class->values[j].value_nick)) {
+ allowed_auth |= 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 MMBearerAllowedAuth value",
+ strings[i]);
+ break;
+ }
+ }
+ }
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ allowed_auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN;
+ }
+
+ g_type_class_unref (flags_class);
+ g_strfreev (strings);
+ return allowed_auth;
+}
+
+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;
+}
+
+/**
+ * mm_get_uint_from_str:
+ * @str: the string to convert to an unsigned int
+ * @out: on success, the number
+ *
+ * Converts a string to an unsigned number. All characters in the string
+ * MUST be valid digits (0 - 9), otherwise FALSE is returned.
+ *
+ * Returns: %TRUE if the string was converted, %FALSE if it was not or if it
+ * did not contain only digits.
+ */
+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 */
+
+gboolean
+mm_utils_ishexstr (const gchar *hex)
+{
+ gsize len;
+ gsize i;
+
+ /* Length not multiple of 2? */
+ len = strlen (hex);
+ if (len % 2 != 0)
+ return FALSE;
+
+ for (i = 0; i < len; i++) {
+ /* Non-hex char? */
+ if (hex[i] >= '0' && hex[i] <= '9')
+ continue;
+ if (hex[i] >= 'a' && hex[i] <= 'f')
+ continue;
+ if (hex[i] >= 'A' && hex[i] <= 'F')
+ continue;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+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;
+}