From d51ff9ac07973701ee790f57c82a99cc25d92ab1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 18 Jan 2012 13:45:03 -0600 Subject: 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. --- src/mm-generic-gsm.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 118 insertions(+), 4 deletions(-) (limited to 'src') 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); } -- cgit v1.2.3-70-g09d2