diff options
Diffstat (limited to 'src')
-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); } |