diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-01-23 15:23:47 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-15 14:14:57 +0100 |
commit | f3ee74c1e871f23564d7e6c5198ed26a8dd35833 (patch) | |
tree | 385a66b229a50e6392da2abc9e0ac8a5e2988898 | |
parent | e975543316f6bf95a21b2db37ec48dd43ef0cec0 (diff) |
broadband-modem: implement default handling of USSD URCs
-rw-r--r-- | src/mm-broadband-modem.c | 133 |
1 files changed, 132 insertions, 1 deletions
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c index 8169455c..24a7ef91 100644 --- a/src/mm-broadband-modem.c +++ b/src/mm-broadband-modem.c @@ -116,6 +116,8 @@ struct _MMBroadbandModemPrivate { /*<--- Modem 3GPP USSD interface --->*/ /* Properties */ GObject *modem_3gpp_ussd_dbus_skeleton; + /* Implementation helpers */ + GSimpleAsyncResult *pending_ussd_action; /*<--- Modem CDMA interface --->*/ /* Properties */ @@ -2861,13 +2863,142 @@ modem_3gpp_ussd_setup_cleanup_unsolicited_result_codes_finish (MMIfaceModem3gppU return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); } +static gchar * +decode_ussd_response (MMBroadbandModem *self, + const gchar *reply) +{ + gchar **items, **iter, *p; + gchar *str = NULL; + gint encoding = -1; + gchar *decoded; + + /* Look for the first ',' */ + p = strchr (reply, ','); + if (!p) + return NULL; + + items = g_strsplit_set (p + 1, " ,", -1); + for (iter = items; iter && *iter; iter++) { + if (*iter[0] == '\0') + continue; + if (str == NULL) + str = *iter; + else if (encoding == -1) { + encoding = atoi (*iter); + mm_dbg ("USSD data coding scheme %d", encoding); + break; /* All done */ + } + } + + if (!str) + return NULL; + + /* Strip quotes */ + if (str[0] == '"') + str++; + p = strchr (str, '"'); + if (p) + *p = '\0'; + + decoded = mm_iface_modem_3gpp_ussd_decode (MM_IFACE_MODEM_3GPP_USSD (self), str); + g_strfreev (items); + return decoded; +} static void cusd_received (MMAtSerialPort *port, GMatchInfo *info, MMBroadbandModem *self) { - /* TODO */ + gint status; + gchar *str; + MMModem3gppUssdSessionState ussd_state = MM_MODEM_3GPP_USSD_SESSION_STATE_IDLE; + + str = g_match_info_fetch (info, 1); + if (!str || !isdigit (*str)) { + mm_warn ("Received invalid USSD response: '%s'", str ? str : "(none)"); + g_free (str); + return; + } + + status = g_ascii_digit_value (*str); + switch (status) { + case 0: /* no further action required */ { + gchar *converted; + + converted = decode_ussd_response (self, str); + if (self->priv->pending_ussd_action) { + /* Response to the user's request */ + g_simple_async_result_set_op_res_gpointer (self->priv->pending_ussd_action, + converted, + g_free); + } else { + /* Network-initiated USSD-Notify */ + mm_iface_modem_3gpp_ussd_update_network_notification ( + MM_IFACE_MODEM_3GPP_USSD (self), + converted); + g_free (converted); + } + break; + } + + case 1: /* further action required */ { + gchar *converted; + + ussd_state = MM_MODEM_3GPP_USSD_SESSION_STATE_USER_RESPONSE; + converted = decode_ussd_response (self, str); + if (self->priv->pending_ussd_action) { + g_simple_async_result_set_op_res_gpointer (self->priv->pending_ussd_action, + converted, + g_free); + } else { + /* Network-initiated USSD-Request */ + mm_iface_modem_3gpp_ussd_update_network_request ( + MM_IFACE_MODEM_3GPP_USSD (self), + converted); + g_free (converted); + } + break; + } + + case 2: + if (self->priv->pending_ussd_action) + g_simple_async_result_set_error (self->priv->pending_ussd_action, + MM_CORE_ERROR, + MM_CORE_ERROR_CANCELLED, + "USSD terminated by network."); + break; + + case 4: + if (self->priv->pending_ussd_action) + g_simple_async_result_set_error (self->priv->pending_ussd_action, + MM_CORE_ERROR, + MM_CORE_ERROR_UNSUPPORTED, + "Operation not supported."); + break; + + default: + if (self->priv->pending_ussd_action) + g_simple_async_result_set_error (self->priv->pending_ussd_action, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Unhandled USSD reply: %s (%d)", + str, + status); + break; + } + + mm_iface_modem_3gpp_ussd_update_state (MM_IFACE_MODEM_3GPP_USSD (self), + ussd_state); + + /* Complete the pending action */ + if (self->priv->pending_ussd_action) { + g_simple_async_result_complete_in_idle (self->priv->pending_ussd_action); + g_object_unref (self->priv->pending_ussd_action); + self->priv->pending_ussd_action = NULL; + } + + g_free (str); } static void |