diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-broadband-modem.c | 26 | ||||
-rw-r--r-- | src/mm-modem-helpers.c | 152 | ||||
-rw-r--r-- | src/mm-modem-helpers.h | 12 | ||||
-rw-r--r-- | src/tests/test-modem-helpers.c | 79 |
4 files changed, 214 insertions, 55 deletions
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c index 895956be..6b3b8e40 100644 --- a/src/mm-broadband-modem.c +++ b/src/mm-broadband-modem.c @@ -3495,16 +3495,21 @@ modem_3gpp_load_operator_code_finish (MMIfaceModem3gpp *self, GError **error) { const gchar *result; - gchar *operator_code; + gchar *operator_code = NULL; result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); if (!result) return NULL; - operator_code = mm_3gpp_parse_operator (result, MM_MODEM_CHARSET_UNKNOWN); - if (operator_code) - mm_dbg ("loaded Operator Code: %s", operator_code); + if (!mm_3gpp_parse_cops_read_response (result, + NULL, /* mode */ + NULL, /* format */ + &operator_code, + NULL, /* act */ + error)) + return NULL; + mm_dbg ("loaded Operator Code: %s", operator_code); return operator_code; } @@ -3531,16 +3536,23 @@ modem_3gpp_load_operator_name_finish (MMIfaceModem3gpp *self, GError **error) { const gchar *result; - gchar *operator_name; + gchar *operator_name = NULL; result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); if (!result) return NULL; - operator_name = mm_3gpp_parse_operator (result, MM_BROADBAND_MODEM (self)->priv->modem_current_charset); + if (!mm_3gpp_parse_cops_read_response (result, + NULL, /* mode */ + NULL, /* format */ + &operator_name, + NULL, /* act */ + error)) + return NULL; + + mm_3gpp_normalize_operator_name (&operator_name, MM_BROADBAND_MODEM (self)->priv->modem_current_charset); if (operator_name) mm_dbg ("loaded Operator Name: %s", operator_name); - return operator_name; } diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index 4a84aa77..ff3aab8f 100644 --- a/src/mm-modem-helpers.c +++ b/src/mm-modem-helpers.c @@ -849,6 +849,89 @@ mm_3gpp_parse_cops_test_response (const gchar *reply, /*************************************************************************/ +gboolean +mm_3gpp_parse_cops_read_response (const gchar *response, + guint *out_mode, + guint *out_format, + gchar **out_operator, + MMModemAccessTechnology *out_act, + GError **error) +{ + GRegex *r; + GMatchInfo *match_info; + GError *inner_error = NULL; + guint mode = 0; + guint format = 0; + gchar *operator = NULL; + guint actval = 0; + MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; + + g_assert (out_mode || out_format || out_operator || out_act); + + /* We assume the response to be either: + * +COPS: <mode>,<format>,<oper> + * or: + * +COPS: <mode>,<format>,<oper>,<AcT> + */ + r = g_regex_new ("\\+COPS:\\s*(\\d+),(\\d+),([^,]*)(?:,(\\d+))?(?:\\r\\n)?", 0, 0, NULL); + g_assert (r != NULL); + + g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); + if (inner_error) + goto out; + + if (!g_match_info_matches (match_info)) { + inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't match response"); + goto out; + } + + if (out_mode && !mm_get_uint_from_match_info (match_info, 1, &mode)) { + inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing mode"); + goto out; + } + + if (out_format && !mm_get_uint_from_match_info (match_info, 2, &format)) { + inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing format"); + goto out; + } + + if (out_operator && !(operator = mm_get_string_unquoted_from_match_info (match_info, 3))) { + inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing operator"); + goto out; + } + + /* AcT is optional */ + if (out_act && g_match_info_get_match_count (match_info) >= 5) { + if (!mm_get_uint_from_match_info (match_info, 4, &actval)) { + inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing AcT"); + goto out; + } + act = get_mm_access_tech_from_etsi_access_tech (actval); + } + +out: + if (match_info) + g_match_info_free (match_info); + g_regex_unref (r); + + if (inner_error) { + g_free (operator); + g_propagate_error (error, inner_error); + return FALSE; + } + + if (out_mode) + *out_mode = mode; + if (out_format) + *out_format = format; + if (out_operator) + *out_operator = operator; + if (out_act) + *out_act = act; + return TRUE; +} + +/*************************************************************************/ static void mm_3gpp_pdp_context_format_free (MM3gppPdpContextFormat *format) @@ -2349,57 +2432,34 @@ mm_string_to_access_tech (const gchar *string) /*************************************************************************/ -gchar * -mm_3gpp_parse_operator (const gchar *reply, - MMModemCharset cur_charset) +void +mm_3gpp_normalize_operator_name (gchar **operator, + MMModemCharset cur_charset) { - gchar *operator = NULL; - - if (reply && !strncmp (reply, "+COPS: ", 7)) { - /* Got valid reply */ - GRegex *r; - GMatchInfo *match_info; - - reply += 7; - r = g_regex_new ("(\\d),(\\d),\"(.+)\"", G_REGEX_UNGREEDY, 0, NULL); - if (!r) - return NULL; + g_assert (operator); - g_regex_match (r, reply, 0, &match_info); - if (g_match_info_matches (match_info)) - operator = g_match_info_fetch (match_info, 3); - - g_match_info_free (match_info); - g_regex_unref (r); - } + if (*operator == NULL) + return; - if (operator) { - /* Some modems (Option & HSO) return the operator name as a hexadecimal - * string of the bytes of the operator name as encoded by the current - * character set. - */ - if (cur_charset == MM_MODEM_CHARSET_UCS2) { - /* In this case we're already checking UTF-8 validity */ - operator = mm_charset_take_and_convert_to_utf8 (operator, MM_MODEM_CHARSET_UCS2); - } - /* Ensure the operator name is valid UTF-8 so that we can send it - * through D-Bus and such. - */ - else if (!g_utf8_validate (operator, -1, NULL)) { - g_free (operator); - return NULL; - } - - /* Some modems (Novatel LTE) return the operator name as "Unknown" when - * it fails to obtain the operator name. Return NULL in such case. - */ - if (operator && g_ascii_strcasecmp (operator, "unknown") == 0) { - g_free (operator); - return NULL; - } + /* Some modems (Option & HSO) return the operator name as a hexadecimal + * string of the bytes of the operator name as encoded by the current + * character set. + */ + if (cur_charset == MM_MODEM_CHARSET_UCS2) { + /* In this case we're already checking UTF-8 validity */ + *operator = mm_charset_take_and_convert_to_utf8 (*operator, MM_MODEM_CHARSET_UCS2); } + /* Ensure the operator name is valid UTF-8 so that we can send it + * through D-Bus and such. + */ + else if (!g_utf8_validate (*operator, -1, NULL)) + g_clear_pointer (operator, g_free); - return operator; + /* Some modems (Novatel LTE) return the operator name as "Unknown" when + * it fails to obtain the operator name. Return NULL in such case. + */ + if (*operator && g_ascii_strcasecmp (*operator, "unknown") == 0) + g_clear_pointer (operator, g_free); } /*************************************************************************/ diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h index 3ab618b2..00536889 100644 --- a/src/mm-modem-helpers.h +++ b/src/mm-modem-helpers.h @@ -116,6 +116,14 @@ void mm_3gpp_network_info_list_free (GList *info_list); GList *mm_3gpp_parse_cops_test_response (const gchar *reply, GError **error); +/* AT+COPS? (current operator) response parser */ +gboolean mm_3gpp_parse_cops_read_response (const gchar *response, + guint *out_mode, + guint *out_format, + gchar **out_operator, + MMModemAccessTechnology *out_act, + GError **error); + /* AT+CGDCONT=? (PDP context format) test parser */ typedef struct { guint min_cid; @@ -240,8 +248,8 @@ gchar *mm_3gpp_facility_to_acronym (MMModem3gppFacility facility); MMModemAccessTechnology mm_string_to_access_tech (const gchar *string); -gchar *mm_3gpp_parse_operator (const gchar *reply, - MMModemCharset cur_charset); +void mm_3gpp_normalize_operator_name (gchar **operator, + MMModemCharset cur_charset); gboolean mm_3gpp_parse_operator_id (const gchar *operator_id, guint16 *mcc, diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c index fc8a9510..054b087e 100644 --- a/src/tests/test-modem-helpers.c +++ b/src/tests/test-modem-helpers.c @@ -689,6 +689,83 @@ test_cops_response_umts_invalid (void *f, gpointer d) } /*****************************************************************************/ +/* Test COPS? responses */ + +typedef struct { + const gchar *str; + guint mode; + guint format; + const gchar *operator; + MMModemAccessTechnology act; +} CopsQueryData; + +static void +test_cops_query_data (const CopsQueryData *item) +{ + gboolean result; + GError *error = NULL; + guint mode = G_MAXUINT; + guint format = G_MAXUINT; + gchar *operator = NULL; + MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; + + result = mm_3gpp_parse_cops_read_response (item->str, + &mode, + &format, + &operator, + &act, + &error); + g_assert_no_error (error); + g_assert (result); + g_assert_cmpuint (mode, ==, item->mode); + g_assert_cmpuint (format, ==, item->format); + g_assert_cmpstr (operator, ==, item->operator); + g_assert_cmpuint (act, ==, item->act); + + g_free (operator); +} + +static const CopsQueryData cops_query_data[] = { + { + .str = "+COPS: 1,0,\"CHINA MOBILE\"", + .mode = 1, + .format = 0, + .operator = "CHINA MOBILE", + .act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN + }, + { + .str = "+COPS: 1,0,\"CHINA MOBILE\",7", + .mode = 1, + .format = 0, + .operator = "CHINA MOBILE", + .act = MM_MODEM_ACCESS_TECHNOLOGY_LTE + }, + { + .str = "+COPS: 1,2,\"46000\"", + .mode = 1, + .format = 2, + .operator = "46000", + .act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN + }, + { + .str = "+COPS: 1,2,\"46000\",7", + .mode = 1, + .format = 2, + .operator = "46000", + .act = MM_MODEM_ACCESS_TECHNOLOGY_LTE + }, +}; + +static void +test_cops_query (void) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (cops_query_data); i++) + test_cops_query_data (&cops_query_data[i]); +} + +/*****************************************************************************/ /* Test CREG/CGREG responses and unsolicited messages */ typedef struct { @@ -2962,6 +3039,8 @@ int main (int argc, char **argv) g_test_suite_add (suite, TESTCASE (test_cops_response_gsm_invalid, NULL)); g_test_suite_add (suite, TESTCASE (test_cops_response_umts_invalid, NULL)); + g_test_suite_add (suite, TESTCASE (test_cops_query, NULL)); + g_test_suite_add (suite, TESTCASE (test_creg1_solicited, reg_data)); g_test_suite_add (suite, TESTCASE (test_creg1_unsolicited, reg_data)); g_test_suite_add (suite, TESTCASE (test_creg2_mercury_solicited, reg_data)); |