aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2011-11-30 09:16:25 +0100
committerAleksander Morgado <aleksander@lanedo.com>2012-03-15 14:14:30 +0100
commit0c7281b2d91a042a810bce4596ce5b061b643926 (patch)
treef4667f513220e43fe3834173f630d1ef3785c512 /src
parentad0a18d10755a53a45245845e0c7b230b10aeab1 (diff)
broadband-modem: implement Operator Code and Name loading
Diffstat (limited to 'src')
-rw-r--r--src/mm-broadband-modem.c105
-rw-r--r--src/mm-modem-helpers.c75
-rw-r--r--src/mm-modem-helpers.h3
3 files changed, 182 insertions, 1 deletions
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
index c08bd29d..695f0457 100644
--- a/src/mm-broadband-modem.c
+++ b/src/mm-broadband-modem.c
@@ -65,6 +65,9 @@ struct _MMBroadbandModemPrivate {
MMModemCapability modem_current_capabilities;
MMModem3gppRegistrationState modem_3gpp_registration_state;
+ /* Modem helpers */
+ MMModemCharset current_charset;
+
/* 3GPP registration helpers */
GPtrArray *reg_regex;
MMModem3gppRegistrationState reg_cs;
@@ -827,8 +830,11 @@ current_charset_ready (MMBroadbandModem *self,
MM_CORE_ERROR_FAILED,
"Modem failed to change character set to %s",
mm_modem_charset_to_string (ctx->charset));
- else
+ else {
+ /* We'll keep track ourselves of the current charset */
+ self->priv->current_charset = current;
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+ }
}
g_simple_async_result_complete (ctx->result);
@@ -1163,6 +1169,98 @@ load_imei (MMIfaceModem3gpp *self,
}
/*****************************************************************************/
+/* Operator Code */
+
+static gchar *
+load_operator_code_finish (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ GVariant *result;
+ gchar *operator_code;
+
+ result = mm_at_sequence_finish (G_OBJECT (self), res, error);
+ if (!result)
+ return NULL;
+
+ operator_code = mm_3gpp_parse_operator (g_variant_get_string (result, NULL),
+ MM_MODEM_CHARSET_UNKNOWN);
+ if (operator_code)
+ mm_dbg ("loaded Operator Code: %s", operator_code);
+
+ g_variant_unref (result);
+ return operator_code;
+}
+
+static const MMAtCommand operator_code_commands[] = {
+ { "+COPS=3,2;+COPS?", 3, (MMAtResponseProcessor)common_parse_string_reply },
+ { NULL }
+};
+
+static void
+load_operator_code (MMIfaceModem3gpp *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ mm_dbg ("loading Operator Code...");
+ mm_at_sequence (G_OBJECT (self),
+ mm_base_modem_get_port_primary (MM_BASE_MODEM (self)),
+ (MMAtCommand *)operator_code_commands,
+ NULL, /* response_processor_context */
+ FALSE,
+ "s",
+ NULL, /* TODO: cancellable */
+ callback,
+ user_data);
+}
+
+/*****************************************************************************/
+/* Operator Name */
+
+static gchar *
+load_operator_name_finish (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ GVariant *result;
+ gchar *operator_name;
+
+ result = mm_at_sequence_finish (G_OBJECT (self), res, error);
+ if (!result)
+ return NULL;
+
+ operator_name = mm_3gpp_parse_operator (g_variant_get_string (result, NULL),
+ MM_MODEM_CHARSET_UNKNOWN);
+ if (operator_name)
+ mm_dbg ("loaded Operator Name: %s", operator_name);
+
+ g_variant_unref (result);
+ return operator_name;
+}
+
+static const MMAtCommand operator_name_commands[] = {
+ { "+COPS=3,0;+COPS?", 3, (MMAtResponseProcessor)common_parse_string_reply },
+ { NULL }
+};
+
+static void
+load_operator_name (MMIfaceModem3gpp *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ mm_dbg ("loading Operator Name...");
+ mm_at_sequence (G_OBJECT (self),
+ mm_base_modem_get_port_primary (MM_BASE_MODEM (self)),
+ (MMAtCommand *)operator_name_commands,
+ NULL, /* response_processor_context */
+ FALSE,
+ "s",
+ NULL, /* TODO: cancellable */
+ callback,
+ user_data);
+}
+
+/*****************************************************************************/
/* Unsolicited registration messages handling (3GPP) */
static void clear_previous_registration_request (MMBroadbandModem *self,
@@ -2302,6 +2400,7 @@ mm_broadband_modem_init (MMBroadbandModem *self)
self->priv->reg_regex = mm_gsm_creg_regex_get (TRUE);
self->priv->reg_cs = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
self->priv->reg_ps = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
+ self->priv->current_charset = MM_MODEM_CHARSET_UNKNOWN;
}
static void
@@ -2367,6 +2466,10 @@ iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
{
iface->load_imei = load_imei;
iface->load_imei_finish = load_imei_finish;
+ iface->load_operator_code = load_operator_code;
+ iface->load_operator_code_finish = load_operator_code_finish;
+ iface->load_operator_name = load_operator_name;
+ iface->load_operator_name_finish = load_operator_name_finish;
iface->setup_unsolicited_registration = setup_unsolicited_registration;
iface->setup_unsolicited_registration_finish = setup_unsolicited_registration_finish;
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index f2383ef8..d046e89e 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -855,6 +855,81 @@ mm_gsm_parse_cscs_support_response (const char *reply,
/*************************************************************************/
+static void
+convert_operator_from_ucs2 (gchar **operator)
+{
+ const gchar *p;
+ gchar *converted;
+ gsize len;
+
+ g_return_if_fail (operator != NULL);
+ g_return_if_fail (*operator != NULL);
+
+ p = *operator;
+ len = strlen (p);
+
+ /* Len needs to be a multiple of 4 for UCS2 */
+ if ((len < 4) || ((len % 4) != 0))
+ return;
+
+ while (*p) {
+ if (!isxdigit (*p++))
+ return;
+ }
+
+ converted = mm_modem_charset_hex_to_utf8 (*operator, MM_MODEM_CHARSET_UCS2);
+ if (converted) {
+ g_free (*operator);
+ *operator = converted;
+ }
+}
+
+gchar *
+mm_3gpp_parse_operator (const gchar *reply,
+ 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_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) {
+ /* 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)
+ convert_operator_from_ucs2 (&operator);
+
+ /* Ensure the operator name is valid UTF-8 so that we can send it
+ * through D-Bus and such.
+ */
+ if (!g_utf8_validate (operator, -1, NULL)) {
+ g_free (operator);
+ operator = NULL;
+ }
+ }
+
+ return operator;
+}
+
+/*************************************************************************/
+
/* Map two letter facility codes into flag values. There are
* many more facilities defined (for various flavors of call
* barring); we only map the ones we care about. */
diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
index 2d69e397..2cec700c 100644
--- a/src/mm-modem-helpers.h
+++ b/src/mm-modem-helpers.h
@@ -63,6 +63,9 @@ gboolean mm_gsm_parse_clck_test_response (const char *reply,
gboolean mm_gsm_parse_clck_response (const char *reply,
gboolean *enabled);
+gchar *mm_3gpp_parse_operator (const gchar *reply,
+ MMModemCharset cur_charset);
+
char *mm_gsm_get_facility_name (MMModemGsmFacility facility);
MMModemGsmAccessTech mm_gsm_string_to_access_tech (const char *string);