aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-01-23 15:23:47 +0100
committerAleksander Morgado <aleksander@lanedo.com>2012-03-15 14:14:57 +0100
commitf3ee74c1e871f23564d7e6c5198ed26a8dd35833 (patch)
tree385a66b229a50e6392da2abc9e0ac8a5e2988898
parente975543316f6bf95a21b2db37ec48dd43ef0cec0 (diff)
broadband-modem: implement default handling of USSD URCs
-rw-r--r--src/mm-broadband-modem.c133
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