diff options
author | Dan Williams <dcbw@redhat.com> | 2012-01-18 13:45:03 -0600 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2012-01-18 13:45:03 -0600 |
commit | d51ff9ac07973701ee790f57c82a99cc25d92ab1 (patch) | |
tree | cb5ab1dc64ac2e600fffa210c05af2282207bb4e /src/mm-generic-gsm.c | |
parent | 43e6039cee57f70b18119a8a68305ec8017f46fb (diff) |
gsm: use PDU modem when the modem doesn't support text mode
Eventually we should be using PDU mode whenever the modem supports
it instead of defaulting to text mode, but there are still some
bugs.
Diffstat (limited to 'src/mm-generic-gsm.c')
-rw-r--r-- | src/mm-generic-gsm.c | 122 |
1 files changed, 118 insertions, 4 deletions
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index eebdbce1..3afe4950 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -136,6 +136,7 @@ typedef struct { * structures. */ GHashTable *sms_parts; + gboolean sms_pdu_mode; guint sms_fetch_pending; @@ -1799,6 +1800,88 @@ clck_cb (MMAtSerialPort *port, mm_serial_port_close (MM_SERIAL_PORT (port)); } +static void +sms_set_format_cb (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + if (error) { + mm_warn ("(%s): failed to set SMS mode, assuming text mode", + mm_port_get_device (MM_PORT (port))); + MM_GENERIC_GSM_GET_PRIVATE (user_data)->sms_pdu_mode = FALSE; + } else { + mm_info ("(%s): using %s mode for SMS", + mm_port_get_device (MM_PORT (port)), + MM_GENERIC_GSM_GET_PRIVATE (user_data)->sms_pdu_mode ? "PDU" : "text"); + } +} + + +#define CMGF_TAG "+CMGF:" + +static void +sms_get_format_cb (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMGenericGsm *self; + MMGenericGsmPrivate *priv; + const char *reply; + GRegex *r; + GMatchInfo *match_info; + char *s; + guint32 min = -1, max = -1; + + if (error) { + mm_warn ("(%s): failed to query SMS mode, assuming text mode", + mm_port_get_device (MM_PORT (port))); + return; + } + + /* Strip whitespace and response tag */ + reply = response->str; + if (g_str_has_prefix (reply, CMGF_TAG)) + reply += strlen (CMGF_TAG); + while (isspace (*reply)) + reply++; + + r = g_regex_new ("\\(?\\s*(\\d+)\\s*[-,]?\\s*(\\d+)?\\s*\\)?", 0, 0, NULL); + if (!r) { + mm_warn ("(%s): failed to parse CMGF query result", mm_port_get_device (MM_PORT (port))); + return; + } + + self = MM_GENERIC_GSM (user_data); + priv = MM_GENERIC_GSM_GET_PRIVATE (self); + if (g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, NULL)) { + s = g_match_info_fetch (match_info, 1); + if (s) + min = atoi (s); + g_free (s); + + s = g_match_info_fetch (match_info, 2); + if (s) + max = atoi (s); + g_free (s); + + /* If the modem only supports PDU mode, use PDUs. + * FIXME: when the PDU code is more robust, default to PDU if the + * modem supports it. + */ + if (min == 0 && max < 1) { + /* Will get reset to FALSE on receipt of error */ + priv->sms_pdu_mode = TRUE; + mm_at_serial_port_queue_command (priv->primary, "AT+CMGF=0", 3, sms_set_format_cb, self); + } else + mm_at_serial_port_queue_command (priv->primary, "AT+CMGF=1", 3, sms_set_format_cb, self); + } + g_match_info_free (match_info); + + g_regex_unref (r); +} + void mm_generic_gsm_enable_complete (MMGenericGsm *self, GError *error, @@ -1849,6 +1932,9 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self, mm_at_serial_port_queue_command (priv->primary, cmd, 3, NULL, NULL); g_free (cmd); + /* Check and enable the right SMS mode */ + mm_at_serial_port_queue_command (priv->primary, "AT+CMGF=?", 3, sms_get_format_cb, self); + /* Enable USSD notifications */ mm_at_serial_port_queue_command (priv->primary, "+CUSD=1", 3, cusd_enable_cb, self); @@ -4669,21 +4755,49 @@ sms_send (MMModemGsmSms *modem, gpointer user_data) { MMCallbackInfo *info; + MMGenericGsm *self = MM_GENERIC_GSM (modem); + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); char *command; MMAtSerialPort *port; info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); - port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error); + port = mm_generic_gsm_get_best_at_port (self, &info->error); if (!port) { mm_callback_info_schedule (info); return; } - /* FIXME: use the PDU mode instead */ - mm_at_serial_port_queue_command (port, "AT+CMGF=1", 3, NULL, NULL); + if (priv->sms_pdu_mode) { + guint8 *pdu; + guint pdulen = 0; + guint smsclen = 0; + char *hex; + + pdu = sms_create_submit_pdu (number, text, smsc, validity, class, &pdulen, &info->error); + if (!pdu) { + mm_callback_info_schedule (info); + return; + } + smsclen = pdu[0]; + + hex = utils_bin2hexstr (pdu, pdulen); + g_free (pdu); + if (hex == NULL) { + g_set_error_literal (&info->error, + MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "Not enough memory to send SMS PDU"); + mm_callback_info_schedule (info); + return; + } + + /* CMGS length is the size of the PDU without SMSC information */ + command = g_strdup_printf ("+CMGS=%d\r%s\x1a", pdulen - smsclen, hex); + g_free (hex); + } else + command = g_strdup_printf ("+CMGS=\"%s\"\r%s\x1a", number, text); - command = g_strdup_printf ("+CMGS=\"%s\"\r%s\x1a", number, text); mm_at_serial_port_queue_command (port, command, 10, sms_send_done, info); g_free (command); } |