diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-02-06 18:12:15 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-15 14:15:00 +0100 |
commit | dc5ff06b4f8c730d8f378ef8d2d5cf985a51e5c5 (patch) | |
tree | 8a34fe4c23a5808e68ec5d2021fe1b86263facb4 /src | |
parent | d9f5779bbbbcf0559a5dd0a3a897b5d4241ad186 (diff) |
broadband-modem: implement generic unsolicited SMS events handling
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-broadband-modem.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c index b559d0dd..8bcb69f3 100644 --- a/src/mm-broadband-modem.c +++ b/src/mm-broadband-modem.c @@ -157,6 +157,7 @@ struct _MMBroadbandModemPrivate { /* Implementation helpers */ gboolean sms_use_pdu_mode; gboolean sms_supported_modes_checked; + GHashTable *known_sms_parts; }; /*****************************************************************************/ @@ -3611,6 +3612,181 @@ modem_messaging_setup_sms_format (MMIfaceModemMessaging *self, } /*****************************************************************************/ +/* Setup/cleanup messaging related unsolicited events (Messaging interface) */ + +static gboolean +modem_messaging_setup_cleanup_unsolicited_events_finish (MMIfaceModemMessaging *self, + GAsyncResult *res, + GError **error) +{ + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); +} + +typedef struct { + MMBroadbandModem *self; + GSimpleAsyncResult *result; + guint idx; +} SmsPartContext; + +static void +sms_part_context_complete_and_free (SmsPartContext *ctx) +{ + g_simple_async_result_complete (ctx->result); + g_object_unref (ctx->result); + g_object_unref (ctx->self); + g_free (ctx); +} + +static void +sms_part_ready (MMBroadbandModem *self, + GAsyncResult *res, + SmsPartContext *ctx) +{ + MMSmsPart *part; + gint rv, status, tpdu_len; + gchar pdu[SMS_MAX_PDU_LEN + 1]; + const gchar *response; + GError *error = NULL; + + response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); + if (error) { + /* We're really ignoring this error afterwards, as we don't have a callback + * passed to the async operation, so just log the error here. */ + mm_warn ("Couldn't retrieve SMS part: '%s'", + error->message); + g_simple_async_result_take_error (ctx->result, error); + sms_part_context_complete_and_free (ctx); + return; + } + + rv = sscanf (response, "+CMGR: %d,,%d %" G_STRINGIFY (SMS_MAX_PDU_LEN) "s", + &status, &tpdu_len, pdu); + if (rv != 3) { + error = g_error_new (MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Failed to parse CMGR response (parsed %d items)", rv); + mm_warn ("Couldn't retrieve SMS part: '%s'", error->message); + g_simple_async_result_take_error (ctx->result, error); + sms_part_context_complete_and_free (ctx); + return; + } + + part = mm_sms_part_new (ctx->idx, pdu, &error); + if (part) { + mm_dbg ("Correctly parsed PDU (%d)", ctx->idx); + mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self), + part, + TRUE); + } else { + /* Don't treat the error as critical */ + mm_dbg ("Error parsing PDU (%d): %s", ctx->idx, error->message); + g_error_free (error); + } + + /* All done */ + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); + sms_part_context_complete_and_free (ctx); +} + +static void +cmti_received (MMAtSerialPort *port, + GMatchInfo *info, + MMBroadbandModem *self) +{ + guint idx = 0; + gchar *str, *command; + SmsPartContext *ctx; + + str = g_match_info_fetch (info, 2); + if (str) + idx = atoi (str); + g_free (str); + + if (G_UNLIKELY (!self->priv->known_sms_parts)) + self->priv->known_sms_parts = g_hash_table_new (g_direct_hash, g_direct_equal); + else if (g_hash_table_lookup_extended (self->priv->known_sms_parts, + GUINT_TO_POINTER (idx), + NULL, + NULL)) + /* Don't signal multiple times if there are multiple CMTI notifications for a message */ + return; + + /* Nothing is currently stored in the hash table - presence is all that matters. */ + g_hash_table_insert (self->priv->known_sms_parts, GUINT_TO_POINTER (idx), NULL); + + ctx = g_new0 (SmsPartContext, 1); + ctx->self = g_object_ref (self); + ctx->result = g_simple_async_result_new (G_OBJECT (self), NULL, NULL, cmti_received); + ctx->idx = idx; + + /* Retrieve the message */ + command = g_strdup_printf ("+CMGR=%d", idx); + mm_base_modem_at_command (MM_BASE_MODEM (self), + command, + 10, + FALSE, + NULL, /* cancellable */ + (GAsyncReadyCallback)sms_part_ready, + ctx); + g_free (command); +} + +static void +set_messaging_unsolicited_events_handlers (MMIfaceModemMessaging *self, + gboolean enable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *result; + MMAtSerialPort *ports[2]; + GRegex *cmti_regex; + guint i; + + result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + set_messaging_unsolicited_events_handlers); + + cmti_regex = mm_3gpp_cmti_regex_get (); + ports[0] = mm_base_modem_get_port_primary (MM_BASE_MODEM (self)); + ports[1] = mm_base_modem_get_port_secondary (MM_BASE_MODEM (self)); + + /* Enable unsolicited events in given port */ + for (i = 0; ports[i] && i < 2; i++) { + /* Set/unset unsolicited CMTI event handler */ + mm_dbg ("%s messaging unsolicited events handlers", + enable ? "Setting" : "Removing"); + mm_at_serial_port_add_unsolicited_msg_handler ( + ports[i], + cmti_regex, + enable ? (MMAtSerialUnsolicitedMsgFn) cmti_received : NULL, + enable ? self : NULL, + NULL); + } + + g_regex_unref (cmti_regex); + g_simple_async_result_set_op_res_gboolean (result, TRUE); + g_simple_async_result_complete_in_idle (result); + g_object_unref (result); +} + +static void +modem_messaging_setup_unsolicited_events (MMIfaceModemMessaging *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + set_messaging_unsolicited_events_handlers (self, TRUE, callback, user_data); +} + +static void +modem_messaging_cleanup_unsolicited_events (MMIfaceModemMessaging *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + set_messaging_unsolicited_events_handlers (self, FALSE, callback, user_data); +} + +/*****************************************************************************/ /* Load initial list of SMS parts (Messaging interface) */ static gboolean @@ -5875,6 +6051,9 @@ finalize (GObject *object) if (self->priv->modem_3gpp_registration_regex) mm_3gpp_creg_regex_destroy (self->priv->modem_3gpp_registration_regex); + if (self->priv->known_sms_parts) + g_hash_table_unref (self->priv->known_sms_parts); + G_OBJECT_CLASS (mm_broadband_modem_parent_class)->finalize (object); } @@ -6091,6 +6270,10 @@ iface_modem_messaging_init (MMIfaceModemMessaging *iface) iface->setup_sms_format_finish = modem_messaging_setup_sms_format_finish; iface->load_initial_sms_parts = modem_messaging_load_initial_sms_parts; iface->load_initial_sms_parts_finish = modem_messaging_load_initial_sms_parts_finish; + iface->setup_unsolicited_events = modem_messaging_setup_unsolicited_events; + iface->setup_unsolicited_events_finish = modem_messaging_setup_cleanup_unsolicited_events_finish; + iface->cleanup_unsolicited_events = modem_messaging_cleanup_unsolicited_events; + iface->cleanup_unsolicited_events_finish = modem_messaging_setup_cleanup_unsolicited_events_finish; } static void |