aboutsummaryrefslogtreecommitdiff
path: root/src/mm-generic-gsm.c
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2012-01-18 13:45:03 -0600
committerDan Williams <dcbw@redhat.com>2012-01-18 13:45:03 -0600
commitd51ff9ac07973701ee790f57c82a99cc25d92ab1 (patch)
treecb5ab1dc64ac2e600fffa210c05af2282207bb4e /src/mm-generic-gsm.c
parent43e6039cee57f70b18119a8a68305ec8017f46fb (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.c122
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);
}