aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/altair/mm-broadband-modem-altair-lte.c26
-rw-r--r--plugins/huawei/mm-broadband-modem-huawei.c12
-rw-r--r--src/mm-broadband-modem.c26
-rw-r--r--src/mm-modem-helpers.c152
-rw-r--r--src/mm-modem-helpers.h12
-rw-r--r--src/tests/test-modem-helpers.c79
6 files changed, 243 insertions, 64 deletions
diff --git a/plugins/altair/mm-broadband-modem-altair-lte.c b/plugins/altair/mm-broadband-modem-altair-lte.c
index 53d516f8..1155a7a1 100644
--- a/plugins/altair/mm-broadband-modem-altair-lte.c
+++ b/plugins/altair/mm-broadband-modem-altair-lte.c
@@ -1065,16 +1065,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;
}
@@ -1109,16 +1114,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_MODEM_CHARSET_UNKNOWN);
+ 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_MODEM_CHARSET_UNKNOWN);
if (operator_name)
mm_dbg ("loaded Operator Name: %s", operator_name);
-
return operator_name;
}
diff --git a/plugins/huawei/mm-broadband-modem-huawei.c b/plugins/huawei/mm-broadband-modem-huawei.c
index ac6964ae..607e14ee 100644
--- a/plugins/huawei/mm-broadband-modem-huawei.c
+++ b/plugins/huawei/mm-broadband-modem-huawei.c
@@ -2179,18 +2179,26 @@ 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;
+ if (!mm_3gpp_parse_cops_read_response (result,
+ NULL, /* mode */
+ NULL, /* format */
+ &operator_name,
+ NULL, /* act */
+ error))
+ return NULL;
+
/* Despite +CSCS? may claim supporting UCS2, Huawei modems always report the
* operator name in ASCII in a +COPS response. Thus, we ignore the current
* charset claimed by the modem and assume the charset is IRA when parsing
* the operator name.
*/
- operator_name = mm_3gpp_parse_operator (result, MM_MODEM_CHARSET_IRA);
+ mm_3gpp_normalize_operator_name (&operator_name, MM_MODEM_CHARSET_IRA);
if (operator_name)
mm_dbg ("loaded Operator Name: %s", operator_name);
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));