diff options
-rw-r--r-- | docs/reference/libmm-glib/libmm-glib-docs.xml | 1 | ||||
-rw-r--r-- | docs/reference/libmm-glib/libmm-glib-sections.txt | 23 | ||||
-rw-r--r-- | introspection/org.freedesktop.ModemManager1.Sim.xml | 14 | ||||
-rw-r--r-- | libmm-glib/Makefile.am | 3 | ||||
-rw-r--r-- | libmm-glib/libmm-glib.h | 1 | ||||
-rw-r--r-- | libmm-glib/mm-sim-preferred-network.c | 167 | ||||
-rw-r--r-- | libmm-glib/mm-sim-preferred-network.h | 68 | ||||
-rw-r--r-- | libmm-glib/mm-sim.c | 42 | ||||
-rw-r--r-- | libmm-glib/mm-sim.h | 2 | ||||
-rw-r--r-- | src/mm-base-sim.c | 135 | ||||
-rw-r--r-- | src/mm-base-sim.h | 8 | ||||
-rw-r--r-- | src/mm-modem-helpers.c | 84 | ||||
-rw-r--r-- | src/mm-modem-helpers.h | 14 |
13 files changed, 562 insertions, 0 deletions
diff --git a/docs/reference/libmm-glib/libmm-glib-docs.xml b/docs/reference/libmm-glib/libmm-glib-docs.xml index 71e74405..81c3cca3 100644 --- a/docs/reference/libmm-glib/libmm-glib-docs.xml +++ b/docs/reference/libmm-glib/libmm-glib-docs.xml @@ -153,6 +153,7 @@ <chapter> <title>The SIM object</title> <xi:include href="xml/mm-sim.xml"/> + <xi:include href="xml/mm-sim-preferred-network.xml"/> </chapter> <chapter> diff --git a/docs/reference/libmm-glib/libmm-glib-sections.txt b/docs/reference/libmm-glib/libmm-glib-sections.txt index 0a72befa..c1daf23a 100644 --- a/docs/reference/libmm-glib/libmm-glib-sections.txt +++ b/docs/reference/libmm-glib/libmm-glib-sections.txt @@ -1215,6 +1215,25 @@ mm_bearer_properties_get_type </SECTION> <SECTION> +<FILE>mm-sim-preferred-network</FILE> +<TITLE>MMSimPreferredNetwork</TITLE> +MMSimPreferredNetwork +mm_sim_preferred_network_get_operator_code +mm_sim_preferred_network_get_access_technology +mm_sim_preferred_network_free +<SUBSECTION Private> +mm_sim_preferred_network_new +mm_sim_preferred_network_new_from_variant +mm_sim_preferred_network_set_access_technology +mm_sim_preferred_network_set_operator_code +mm_sim_preferred_network_get_tuple +mm_sim_preferred_network_list_get_variant +<SUBSECTION Standard> +MM_TYPE_SIM_PREFERRED_NETWORK +mm_sim_preferred_network_get_type +</SECTION> + +<SECTION> <FILE>mm-sim</FILE> <TITLE>MMSim</TITLE> MMSim @@ -1234,6 +1253,7 @@ mm_sim_get_operator_name mm_sim_dup_operator_name mm_sim_get_emergency_numbers mm_sim_dup_emergency_numbers +mm_sim_get_preferred_networks <SUBSECTION Methods> mm_sim_send_pin mm_sim_send_pin_finish @@ -3125,6 +3145,8 @@ mm_gdbus_sim_get_operator_name mm_gdbus_sim_dup_operator_name mm_gdbus_sim_get_emergency_numbers mm_gdbus_sim_dup_emergency_numbers +mm_gdbus_sim_dup_preferred_networks +mm_gdbus_sim_get_preferred_networks <SUBSECTION Methods> mm_gdbus_sim_call_send_pin mm_gdbus_sim_call_send_pin_finish @@ -3146,6 +3168,7 @@ mm_gdbus_sim_set_operator_identifier mm_gdbus_sim_set_operator_name mm_gdbus_sim_set_sim_identifier mm_gdbus_sim_set_emergency_numbers +mm_gdbus_sim_set_preferred_networks mm_gdbus_sim_complete_change_pin mm_gdbus_sim_complete_enable_pin mm_gdbus_sim_complete_send_pin diff --git a/introspection/org.freedesktop.ModemManager1.Sim.xml b/introspection/org.freedesktop.ModemManager1.Sim.xml index 87891e31..63d0e9b7 100644 --- a/introspection/org.freedesktop.ModemManager1.Sim.xml +++ b/introspection/org.freedesktop.ModemManager1.Sim.xml @@ -127,5 +127,19 @@ --> <property name="EmergencyNumbers" type="as" access="read" /> + <!-- + PreferredNetworks: + + List of preferred networks with access technologies configured in the SIM card. + + Each entry contains an operator id string (<literal>"MCCMNC"</literal>) + consisting of 5 or 6 digits, and an + <link linkend="MMModemAccessTechnology">MMModemAccessTechnology</link> mask. + If the SIM card does not support access technology storage, the mask will be + set to <link linkend="MM-MODEM-ACCESS-TECHNOLOGY-UNKNOWN:CAPS"> + MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN</link>. + --> + <property name="PreferredNetworks" type="a(su)" access="read" /> + </interface> </node> diff --git a/libmm-glib/Makefile.am b/libmm-glib/Makefile.am index 49f1e832..f33836f2 100644 --- a/libmm-glib/Makefile.am +++ b/libmm-glib/Makefile.am @@ -89,6 +89,8 @@ libmm_glib_la_SOURCES = \ mm-pco.c \ mm-call-audio-format.h \ mm-call-audio-format.c \ + mm-sim-preferred-network.h \ + mm-sim-preferred-network.c \ $(NULL) libmm_glib_la_CPPFLAGS = \ @@ -160,6 +162,7 @@ include_HEADERS = \ mm-kernel-event-properties.h \ mm-pco.h \ mm-call-audio-format.h \ + mm-sim-preferred-network.h \ $(NULL) CLEANFILES = diff --git a/libmm-glib/libmm-glib.h b/libmm-glib/libmm-glib.h index e4504894..6572b2d3 100644 --- a/libmm-glib/libmm-glib.h +++ b/libmm-glib/libmm-glib.h @@ -80,6 +80,7 @@ #include <mm-signal.h> #include <mm-kernel-event-properties.h> #include <mm-pco.h> +#include <mm-sim-preferred-network.h> /* generated */ #include <mm-errors-types.h> diff --git a/libmm-glib/mm-sim-preferred-network.c b/libmm-glib/mm-sim-preferred-network.c new file mode 100644 index 00000000..c53239dd --- /dev/null +++ b/libmm-glib/mm-sim-preferred-network.c @@ -0,0 +1,167 @@ +/* -*- 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) 2021 UROS Ltd + */ + +#include "mm-sim-preferred-network.h" + +struct _MMSimPreferredNetwork { + gchar *operator_code; + MMModemAccessTechnology access_technology; +}; + +static MMSimPreferredNetwork * +mm_sim_preferred_network_copy (MMSimPreferredNetwork *preferred_network) +{ + MMSimPreferredNetwork *preferred_network_copy; + + preferred_network_copy = g_slice_new0 (MMSimPreferredNetwork); + preferred_network_copy->operator_code = g_strdup (preferred_network->operator_code); + preferred_network_copy->access_technology = preferred_network->access_technology; + + return preferred_network_copy; +} + +G_DEFINE_BOXED_TYPE (MMSimPreferredNetwork, mm_sim_preferred_network, (GBoxedCopyFunc) mm_sim_preferred_network_copy, (GBoxedFreeFunc) mm_sim_preferred_network_free) + +/** + * mm_sim_preferred_network_free: + * @self: A #MMSimPreferredNetwork. + * + * Frees a #MMSimPreferredNetwork. + * + * Since: 1.18 + */ +void +mm_sim_preferred_network_free (MMSimPreferredNetwork *self) +{ + if (!self) + return; + + g_free (self->operator_code); + g_slice_free (MMSimPreferredNetwork, self); +} + +/** + * mm_sim_preferred_network_get_operator_code: + * @self: A #MMSimPreferredNetwork. + * + * Get the operator code (MCCMNC) of the preferred network. + * + * Returns: (transfer none): The operator code, or %NULL if none available. + * + * Since: 1.18 + */ +const gchar * +mm_sim_preferred_network_get_operator_code (const MMSimPreferredNetwork *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + return self->operator_code; +} + +/** + * mm_sim_preferred_network_get_access_technology: + * @self: A #MMSimPreferredNetwork. + * + * Get the access technology mask of the preferred network. + * + * Returns: A #MMModemAccessTechnology. + * + * Since: 1.18 + */ +MMModemAccessTechnology +mm_sim_preferred_network_get_access_technology (const MMSimPreferredNetwork *self) +{ + g_return_val_if_fail (self != NULL, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN); + + return self->access_technology; +} + +/** + * mm_sim_preferred_network_set_operator_code: (skip) + */ +void +mm_sim_preferred_network_set_operator_code (MMSimPreferredNetwork *self, + const gchar *operator_code) +{ + g_return_if_fail (self != NULL); + + g_free (self->operator_code); + self->operator_code = g_strdup (operator_code); +} + +/** + * mm_sim_preferred_network_set_access_technology: (skip) + */ +void +mm_sim_preferred_network_set_access_technology (MMSimPreferredNetwork *self, + MMModemAccessTechnology access_technology) +{ + g_return_if_fail (self != NULL); + + self->access_technology = access_technology; +} + +/** + * mm_sim_preferred_network_new: (skip) + */ +MMSimPreferredNetwork * +mm_sim_preferred_network_new (void) +{ + return g_slice_new0 (MMSimPreferredNetwork); +} + +/** + * mm_sim_preferred_network_new_from_variant: (skip) + */ +MMSimPreferredNetwork * +mm_sim_preferred_network_new_from_variant (GVariant *variant) +{ + MMSimPreferredNetwork *preferred_net; + + g_return_val_if_fail (g_variant_is_of_type (variant, G_VARIANT_TYPE ("(su)")), + NULL); + + preferred_net = mm_sim_preferred_network_new (); + g_variant_get (variant, "(su)", &preferred_net->operator_code, &preferred_net->access_technology); + return preferred_net; +} + +/** + * mm_sim_preferred_network_get_tuple: (skip) + */ +GVariant * +mm_sim_preferred_network_get_tuple (const MMSimPreferredNetwork *self) +{ + return g_variant_new ("(su)", + self->operator_code, + self->access_technology); +} + +/** + * mm_sim_preferred_network_list_get_variant: (skip) + */ +GVariant * +mm_sim_preferred_network_list_get_variant (const GList *preferred_network_list) +{ + GVariantBuilder builder; + const GList *iter; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(su)")); + for (iter = preferred_network_list; iter; iter = g_list_next (iter)) { + g_variant_builder_add_value (&builder, + mm_sim_preferred_network_get_tuple ((const MMSimPreferredNetwork *) iter->data)); + } + return g_variant_builder_end (&builder); +} diff --git a/libmm-glib/mm-sim-preferred-network.h b/libmm-glib/mm-sim-preferred-network.h new file mode 100644 index 00000000..e6042587 --- /dev/null +++ b/libmm-glib/mm-sim-preferred-network.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) 2021 UROS Ltd + */ + +#ifndef MM_SIM_PREFERRED_NETWORK_H +#define MM_SIM_PREFERRED_NETWORK_H + +#if !defined (__LIBMM_GLIB_H_INSIDE__) && !defined (LIBMM_GLIB_COMPILATION) +#error "Only <libmm-glib.h> can be included directly." +#endif + +#include <ModemManager.h> +#include <glib-object.h> + +G_BEGIN_DECLS + +/** + * MMSimPreferredNetwork: + * + * The #MMSimPreferredNetwork structure contains private data and should only be accessed + * using the provided API. + */ +typedef struct _MMSimPreferredNetwork MMSimPreferredNetwork; + +#define MM_TYPE_SIM_PREFERRED_NETWORK (mm_sim_preferred_network_get_type ()) +GType mm_sim_preferred_network_get_type (void); + +const gchar *mm_sim_preferred_network_get_operator_code (const MMSimPreferredNetwork *self); +MMModemAccessTechnology mm_sim_preferred_network_get_access_technology (const MMSimPreferredNetwork *self); + +void mm_sim_preferred_network_free (MMSimPreferredNetwork *self); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSimPreferredNetwork, mm_sim_preferred_network_free) + +/*****************************************************************************/ +/* ModemManager/libmm-glib/mmcli specific methods */ + +#if defined (_LIBMM_INSIDE_MM) || \ + defined (_LIBMM_INSIDE_MMCLI) || \ + defined (LIBMM_GLIB_COMPILATION) + +MMSimPreferredNetwork * mm_sim_preferred_network_new (void); +MMSimPreferredNetwork * mm_sim_preferred_network_new_from_variant (GVariant *variant); + +void mm_sim_preferred_network_set_operator_code (MMSimPreferredNetwork *self, + const gchar *operator_code); +void mm_sim_preferred_network_set_access_technology (MMSimPreferredNetwork *self, + MMModemAccessTechnology access_technology); + +GVariant *mm_sim_preferred_network_get_tuple (const MMSimPreferredNetwork *self); +GVariant *mm_sim_preferred_network_list_get_variant (const GList *preferred_network_list); + +#endif + +G_END_DECLS + +#endif /* MM_SIM_PREFERRED_NETWORK_H */ diff --git a/libmm-glib/mm-sim.c b/libmm-glib/mm-sim.c index 0a3b6071..ac509d3e 100644 --- a/libmm-glib/mm-sim.c +++ b/libmm-glib/mm-sim.c @@ -23,6 +23,7 @@ #include "mm-helpers.h" #include "mm-sim.h" +#include "mm-sim-preferred-network.h" /** * SECTION: mm-sim @@ -860,6 +861,47 @@ mm_sim_change_pin_sync (MMSim *self, /*****************************************************************************/ +/** + * mm_sim_get_preferred_networks: + * @self: A #MMSim. + * + * Gets the list of #MMSimPreferredNetwork objects exposed by this + * #MMSim. + * + * Returns: (transfer full) (element-type ModemManager.SimPreferredNetwork): a list of + * #MMSimPreferredNetwork objects, or #NULL. The returned value should + * be freed with g_list_free_full() using mm_sim_preferred_network_free() as #GDestroyNotify + * function. + * + * Since: 1.18 + */ +GList * +mm_sim_get_preferred_networks (MMSim *self) +{ + GList *network_list = NULL; + GVariant *container, *child; + GVariantIter iter; + + g_return_val_if_fail (MM_IS_SIM (self), NULL); + + container = mm_gdbus_sim_get_preferred_networks (MM_GDBUS_SIM (self)); + g_return_val_if_fail (g_variant_is_of_type (container, G_VARIANT_TYPE ("a(su)")), NULL); + + g_variant_iter_init (&iter, container); + while ((child = g_variant_iter_next_value (&iter))) { + MMSimPreferredNetwork *preferred_net; + + preferred_net = mm_sim_preferred_network_new_from_variant (child); + if (preferred_net) + network_list = g_list_append (network_list, preferred_net); + g_variant_unref (child); + } + + return network_list; +} + +/*****************************************************************************/ + static void mm_sim_init (MMSim *self) { diff --git a/libmm-glib/mm-sim.h b/libmm-glib/mm-sim.h index 3449e289..8ebf069f 100644 --- a/libmm-glib/mm-sim.h +++ b/libmm-glib/mm-sim.h @@ -87,6 +87,8 @@ gchar *mm_sim_dup_operator_name (MMSim *self); const gchar * const *mm_sim_get_emergency_numbers (MMSim *self); gchar **mm_sim_dup_emergency_numbers (MMSim *self); +GList* mm_sim_get_preferred_networks (MMSim *self); + void mm_sim_send_pin (MMSim *self, const gchar *pin, GCancellable *cancellable, diff --git a/src/mm-base-sim.c b/src/mm-base-sim.c index c8bd32d4..a3275fc1 100644 --- a/src/mm-base-sim.c +++ b/src/mm-base-sim.c @@ -1141,6 +1141,101 @@ load_emergency_numbers (MMBaseSim *self, } /*****************************************************************************/ +/* Preferred networks */ + +static GList * +parse_preferred_networks (const gchar *response, + GError **error) +{ + gchar **entries; + gchar **iter; + GList *result = NULL; + + entries = g_strsplit_set (response, "\r\n", -1); + for (iter = entries; iter && *iter; iter++) { + gchar *operator_code = NULL; + gboolean gsm_act; + gboolean gsm_compact_act; + gboolean utran_act; + gboolean eutran_act; + gboolean ngran_act; + MMSimPreferredNetwork *preferred_network = NULL; + MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; + + g_strstrip (*iter); + if (strlen (*iter) == 0) + continue; + + if (mm_sim_parse_cpol_query_response (*iter, + &operator_code, + &gsm_act, + &gsm_compact_act, + &utran_act, + &eutran_act, + &ngran_act, + error)) { + preferred_network = mm_sim_preferred_network_new (); + mm_sim_preferred_network_set_operator_code (preferred_network, operator_code); + if (gsm_act) + act |= MM_MODEM_ACCESS_TECHNOLOGY_GSM; + if (gsm_compact_act) + act |= MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT; + if (utran_act) + act |= MM_MODEM_ACCESS_TECHNOLOGY_UMTS; + if (eutran_act) + act |= MM_MODEM_ACCESS_TECHNOLOGY_LTE; + if (ngran_act) + act |= MM_MODEM_ACCESS_TECHNOLOGY_5GNR; + mm_sim_preferred_network_set_access_technology (preferred_network, act); + result = g_list_append (result, preferred_network); + } else + break; + g_free (operator_code); + } + g_strfreev (entries); + + return result; +} + +static GList * +load_preferred_networks_finish (MMBaseSim *self, + GAsyncResult *res, + GError **error) +{ + gchar *result; + GList *preferred_network_list; + + result = g_task_propagate_pointer (G_TASK (res), error); + if (!result) + return NULL; + + preferred_network_list = parse_preferred_networks (result, error); + mm_obj_dbg (self, "loaded %u preferred networks", g_list_length (preferred_network_list)); + + g_free (result); + + return preferred_network_list; +} + +STR_REPLY_READY_FN (load_preferred_networks) + +static void +load_preferred_networks (MMBaseSim *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + mm_obj_dbg (self, "loading preferred networks..."); + + mm_base_modem_at_command ( + self->priv->modem, + "+CPOL?", + 20, + FALSE, + (GAsyncReadyCallback)load_preferred_networks_command_ready, + g_task_new (self, NULL, callback, user_data)); +} + +/*****************************************************************************/ /* ICCID */ static gchar * @@ -1525,6 +1620,7 @@ typedef enum { INITIALIZATION_STEP_OPERATOR_ID, INITIALIZATION_STEP_OPERATOR_NAME, INITIALIZATION_STEP_EMERGENCY_NUMBERS, + INITIALIZATION_STEP_PREFERRED_NETWORKS, INITIALIZATION_STEP_LAST } InitializationStep; @@ -1623,6 +1719,31 @@ init_load_emergency_numbers_ready (MMBaseSim *self, interface_initialization_step (task); } +static void +init_load_preferred_networks_ready (MMBaseSim *self, + GAsyncResult *res, + GTask *task) +{ + InitAsyncContext *ctx; + GError *error = NULL; + GList *preferred_nets_list; + + preferred_nets_list = MM_BASE_SIM_GET_CLASS (self)->load_preferred_networks_finish (self, res, &error); + if (error) { + mm_obj_warn (self, "couldn't load list of preferred networks: %s", error->message); + g_error_free (error); + } + + mm_gdbus_sim_set_preferred_networks (MM_GDBUS_SIM (self), + mm_sim_preferred_network_list_get_variant (preferred_nets_list)); + g_list_free_full (preferred_nets_list, (GDestroyNotify) mm_sim_preferred_network_free); + + /* Go on to next step */ + ctx = g_task_get_task_data (task); + ctx->step++; + interface_initialization_step (task); +} + #undef STR_REPLY_READY_FN #define STR_REPLY_READY_FN(NAME,DISPLAY) \ static void \ @@ -1798,6 +1919,18 @@ interface_initialization_step (GTask *task) ctx->step++; /* Fall through */ + case INITIALIZATION_STEP_PREFERRED_NETWORKS: + if (MM_BASE_SIM_GET_CLASS (self)->load_preferred_networks && + MM_BASE_SIM_GET_CLASS (self)->load_preferred_networks_finish) { + MM_BASE_SIM_GET_CLASS (self)->load_preferred_networks ( + self, + (GAsyncReadyCallback)init_load_preferred_networks_ready, + task); + return; + } + ctx->step++; + /* Fall through */ + case INITIALIZATION_STEP_LAST: /* We are done without errors! */ g_task_return_boolean (task, TRUE); @@ -2051,6 +2184,8 @@ mm_base_sim_class_init (MMBaseSimClass *klass) klass->load_operator_name_finish = load_operator_name_finish; klass->load_emergency_numbers = load_emergency_numbers; klass->load_emergency_numbers_finish = load_emergency_numbers_finish; + klass->load_preferred_networks = load_preferred_networks; + klass->load_preferred_networks_finish = load_preferred_networks_finish; klass->send_pin = send_pin; klass->send_pin_finish = common_send_pin_puk_finish; klass->send_puk = send_puk; diff --git a/src/mm-base-sim.h b/src/mm-base-sim.h index ed582528..67f2690d 100644 --- a/src/mm-base-sim.h +++ b/src/mm-base-sim.h @@ -150,6 +150,14 @@ struct _MMBaseSimClass { /* Signals */ void (* pin_lock_enabled) (MMBaseSim *self, gboolean enabled); + + /* Load preferred networks (async) */ + void (* load_preferred_networks) (MMBaseSim *self, + GAsyncReadyCallback callback, + gpointer user_data); + GList * (* load_preferred_networks_finish) (MMBaseSim *self, + GAsyncResult *res, + GError **error); }; GType mm_base_sim_get_type (void); diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index 26b55f71..b6b7f113 100644 --- a/src/mm-modem-helpers.c +++ b/src/mm-modem-helpers.c @@ -5126,3 +5126,87 @@ out: g_strfreev (split); return valid; } + +/*****************************************************************************/ + +gboolean +mm_sim_parse_cpol_query_response (const gchar *response, + gchar **out_operator_code, + gboolean *out_gsm_act, + gboolean *out_gsm_compact_act, + gboolean *out_utran_act, + gboolean *out_eutran_act, + gboolean *out_ngran_act, + GError **error) +{ + g_autoptr(GMatchInfo) match_info = NULL; + g_autoptr(GRegex) r = NULL; + g_autofree gchar *operator_code = NULL; + guint format = 0; + guint act = 0; + guint match_count; + + r = g_regex_new ("\\+CPOL:\\s*\\d+,\\s*(\\d+),\\s*\"(\\d+)\"" + "(?:,\\s*(\\d+))?" /* GSM_AcTn */ + "(?:,\\s*(\\d+))?" /* GSM_Compact_AcTn */ + "(?:,\\s*(\\d+))?" /* UTRAN_AcTn */ + "(?:,\\s*(\\d+))?" /* E-UTRAN_AcTn */ + "(?:,\\s*(\\d+))?", /* NG-RAN_AcTn */ + G_REGEX_RAW, 0, NULL); + g_regex_match (r, response, 0, &match_info); + + if (!g_match_info_matches (match_info)) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Couldn't parse +CPOL reply: %s", response); + return FALSE; + } + + match_count = g_match_info_get_match_count (match_info); + /* Remember that g_match_info_get_match_count() includes match #0 */ + g_assert (match_count >= 3); + + if (!mm_get_uint_from_match_info (match_info, 1, &format) || + !(operator_code = mm_get_string_unquoted_from_match_info (match_info, 2))) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Couldn't parse +CPOL reply parameters: %s", response); + return FALSE; + } + + if (format != 2) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "+CPOL reply not using numeric operator code: %s", response); + return FALSE; + } + + if (out_operator_code) { + *out_operator_code = g_steal_pointer (&operator_code); + } + if (out_gsm_act) + *out_gsm_act = match_count >= 4 && + mm_get_uint_from_match_info (match_info, 3, &act) && + act != 0; + if (out_gsm_compact_act) + *out_gsm_compact_act = match_count >= 5 && + mm_get_uint_from_match_info (match_info, 4, &act) && + act != 0; + if (out_utran_act) + *out_utran_act = match_count >= 6 && + mm_get_uint_from_match_info (match_info, 5, &act) && + act != 0; + if (out_eutran_act) + *out_eutran_act = match_count >= 7 && + mm_get_uint_from_match_info (match_info, 6, &act) && + act != 0; + if (out_ngran_act) + *out_ngran_act = match_count >= 8 && + mm_get_uint_from_match_info (match_info, 7, &act) && + act != 0; + + return TRUE; +} diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h index 0f314959..806a8e79 100644 --- a/src/mm-modem-helpers.h +++ b/src/mm-modem-helpers.h @@ -521,6 +521,20 @@ gboolean mm_parse_supl_address (const gchar *supl, GError **error); /*****************************************************************************/ +/* SIM specific helpers and utilities */ +/*****************************************************************************/ + +/* +CPOL? response parser (for a single entry) - accepts only numeric operator format*/ +gboolean mm_sim_parse_cpol_query_response (const gchar *response, + gchar **out_operator_code, + gboolean *out_gsm_act, + gboolean *out_gsm_compact_act, + gboolean *out_utran_act, + gboolean *out_eutran_act, + gboolean *out_ngran_act, + GError **error); + +/*****************************************************************************/ /* Useful when clamp-ing an unsigned integer with implicit low limit set to 0, * and in order to avoid -Wtype-limits warnings. */ |