sms: fix sending SMS messages on some modems

This is the port to git master of the following commit:

commit 65f13f41cfd00cd38f118121a58b83713501f45f
Author: Dan Williams <dcbw@redhat.com>
Date:   Tue Jul 17 16:00:31 2012 -0500

    gsm: fix sending SMS messages on some modems and use PDU by default

    It turns out we really do have to wait for the modem to return the
    ">" prompt before sending the message data, otherwise a number of
    modems will complain about the data and fail the message.  Fix that
    by sending the first bit of the CMGS, waiting for the ">", and then
    sending the rest.

    This also switches all modems over to PDU mode by default if they
    support it, since it's more compatible and most recent modems don't
    even bother to support text mode anyway.
This commit is contained in:
Aleksander Morgado
2012-08-24 12:01:01 +02:00
parent 4fe7c7d637
commit ba4e209745
2 changed files with 106 additions and 33 deletions

View File

@@ -83,6 +83,7 @@ typedef struct {
/* Regular expressions for successful replies */
GRegex *regex_ok;
GRegex *regex_connect;
GRegex *regex_sms;
GRegex *regex_custom_successful;
/* Regular expressions for error replies */
GRegex *regex_cme_error;
@@ -105,6 +106,7 @@ mm_serial_parser_v1_new (void)
parser->regex_ok = g_regex_new ("\\r\\nOK(\\r\\n)+$", flags, 0, NULL);
parser->regex_connect = g_regex_new ("\\r\\nCONNECT.*\\r\\n", flags, 0, NULL);
parser->regex_sms = g_regex_new ("\\r\\n>\\s*$", flags, 0, NULL);
parser->regex_cme_error = g_regex_new ("\\r\\n\\+CME ERROR:\\s*(\\d+)\\r\\n$", flags, 0, NULL);
parser->regex_cms_error = g_regex_new ("\\r\\n\\+CMS ERROR:\\s*(\\d+)\\r\\n$", flags, 0, NULL);
parser->regex_cme_error_str = g_regex_new ("\\r\\n\\+CME ERROR:\\s*([^\\n\\r]+)\\r\\n$", flags, 0, NULL);
@@ -173,10 +175,18 @@ mm_serial_parser_v1_parse (gpointer data,
0, 0, NULL, NULL);
if (found)
remove_matches (parser->regex_ok, response);
else
found = g_regex_match_full (parser->regex_connect,
response->str, response->len,
0, 0, NULL, NULL);
}
if (!found) {
found = g_regex_match_full (parser->regex_connect,
response->str, response->len,
0, 0, NULL, NULL);
}
if (!found) {
found = g_regex_match_full (parser->regex_sms,
response->str, response->len,
0, 0, NULL, NULL);
}
if (found) {
@@ -328,6 +338,7 @@ mm_serial_parser_v1_destroy (gpointer data)
g_regex_unref (parser->regex_ok);
g_regex_unref (parser->regex_connect);
g_regex_unref (parser->regex_sms);
g_regex_unref (parser->regex_cme_error);
g_regex_unref (parser->regex_cms_error);
g_regex_unref (parser->regex_cme_error_str);

View File

@@ -404,20 +404,23 @@ mm_sms_has_part_index (MMSms *self,
/*****************************************************************************/
static gchar *
static gboolean
sms_get_store_or_send_command (MMSmsPart *part,
gboolean text_or_pdu, /* TRUE for PDU */
gboolean store_or_send, /* TRUE for send */
gchar **out_cmd,
gchar **out_msg_data,
GError **error)
{
gchar *cmd;
g_assert (out_cmd != NULL);
g_assert (out_msg_data != NULL);
if (!text_or_pdu) {
/* Text mode */
cmd = g_strdup_printf ("+CMG%c=\"%s\"\r%s\x1a",
store_or_send ? 'S' : 'W',
mm_sms_part_get_number (part),
mm_sms_part_get_text (part));
*out_cmd = g_strdup_printf ("+CMG%c=\"%s\"",
store_or_send ? 'S' : 'W',
mm_sms_part_get_number (part));
*out_msg_data = g_strdup_printf ("%s\x1a", mm_sms_part_get_text (part));
} else {
guint8 *pdu;
guint pdulen = 0;
@@ -428,7 +431,8 @@ sms_get_store_or_send_command (MMSmsPart *part,
pdu = mm_sms_part_get_submit_pdu (part, &pdulen, &msgstart, error);
if (!pdu)
return NULL;
/* 'error' should already be set */
return FALSE;
/* Convert PDU to hex */
hex = utils_bin2hexstr (pdu, pdulen);
@@ -439,18 +443,18 @@ sms_get_store_or_send_command (MMSmsPart *part,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Not enough memory to send SMS PDU");
return NULL;
return FALSE;
}
/* CMGW/S length is the size of the PDU without SMSC information */
cmd = g_strdup_printf ("+CMG%c=%d\r%s\x1a",
store_or_send ? 'S' : 'W',
pdulen - msgstart,
hex);
*out_cmd = g_strdup_printf ("+CMG%c=%d",
store_or_send ? 'S' : 'W',
pdulen - msgstart);
*out_msg_data = g_strdup_printf ("%s\x1a", hex);
g_free (hex);
}
return cmd;
return TRUE;
}
/*****************************************************************************/
@@ -459,6 +463,7 @@ sms_get_store_or_send_command (MMSmsPart *part,
typedef struct {
MMSms *self;
MMBaseModem *modem;
char *msg_data;
GSimpleAsyncResult *result;
} SmsStoreContext;
@@ -469,6 +474,7 @@ sms_store_context_complete_and_free (SmsStoreContext *ctx)
g_object_unref (ctx->result);
g_object_unref (ctx->modem);
g_object_unref (ctx->self);
g_free (ctx->msg_data);
g_free (ctx);
}
@@ -481,9 +487,9 @@ sms_store_finish (MMSms *self,
}
static void
store_ready (MMBaseModem *modem,
GAsyncResult *res,
SmsStoreContext *ctx)
store_msg_data_ready (MMBaseModem *modem,
GAsyncResult *res,
SmsStoreContext *ctx)
{
const gchar *response;
GError *error = NULL;
@@ -517,6 +523,30 @@ store_ready (MMBaseModem *modem,
sms_store_context_complete_and_free (ctx);
}
static void
store_ready (MMBaseModem *modem,
GAsyncResult *res,
SmsStoreContext *ctx)
{
const gchar *response;
GError *error = NULL;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (modem), res, &error);
if (error) {
g_simple_async_result_take_error (ctx->result, error);
sms_store_context_complete_and_free (ctx);
return;
}
/* Send the actual message data */
mm_base_modem_at_command_raw (ctx->modem,
ctx->msg_data,
10,
FALSE,
(GAsyncReadyCallback) store_msg_data_ready,
ctx);
}
static void
sms_store (MMSms *self,
GAsyncReadyCallback callback,
@@ -554,16 +584,20 @@ sms_store (MMSms *self,
MM_IFACE_MODEM_MESSAGING_SMS_PDU_MODE, &use_pdu_mode,
NULL);
cmd = sms_get_store_or_send_command ((MMSmsPart *)ctx->self->priv->parts->data,
use_pdu_mode,
FALSE,
&error);
if (!cmd) {
if (!sms_get_store_or_send_command ((MMSmsPart *)ctx->self->priv->parts->data,
use_pdu_mode,
FALSE,
&cmd,
&ctx->msg_data,
&error)) {
g_simple_async_result_take_error (ctx->result, error);
sms_store_context_complete_and_free (ctx);
return;
}
g_assert (cmd != NULL);
g_assert (ctx->msg_data != NULL);
mm_base_modem_at_command (ctx->modem,
cmd,
10,
@@ -579,6 +613,7 @@ sms_store (MMSms *self,
typedef struct {
MMSms *self;
MMBaseModem *modem;
char *msg_data;
GSimpleAsyncResult *result;
} SmsSendContext;
@@ -601,9 +636,9 @@ sms_send_finish (MMSms *self,
}
static void
send_generic_ready (MMBaseModem *modem,
GAsyncResult *res,
SmsSendContext *ctx)
send_generic_msg_data_ready (MMBaseModem *modem,
GAsyncResult *res,
SmsSendContext *ctx)
{
GError *error = NULL;
@@ -618,6 +653,29 @@ send_generic_ready (MMBaseModem *modem,
sms_send_context_complete_and_free (ctx);
}
static void
send_generic_ready (MMBaseModem *modem,
GAsyncResult *res,
SmsSendContext *ctx)
{
GError *error = NULL;
mm_base_modem_at_command_finish (MM_BASE_MODEM (modem), res, &error);
if (error) {
g_simple_async_result_take_error (ctx->result, error);
sms_send_context_complete_and_free (ctx);
return;
}
/* Send the actual message data */
mm_base_modem_at_command_raw (ctx->modem,
ctx->msg_data,
10,
FALSE,
(GAsyncReadyCallback)send_generic_msg_data_ready,
ctx);
}
static void
sms_send_generic (SmsSendContext *ctx)
{
@@ -630,16 +688,20 @@ sms_send_generic (SmsSendContext *ctx)
MM_IFACE_MODEM_MESSAGING_SMS_PDU_MODE, &use_pdu_mode,
NULL);
cmd = sms_get_store_or_send_command ((MMSmsPart *)ctx->self->priv->parts->data,
use_pdu_mode,
FALSE,
&error);
if (!cmd) {
if (!sms_get_store_or_send_command ((MMSmsPart *)ctx->self->priv->parts->data,
use_pdu_mode,
TRUE,
&cmd,
&ctx->msg_data,
&error)) {
g_simple_async_result_take_error (ctx->result, error);
sms_send_context_complete_and_free (ctx);
return;
}
g_assert (cmd != NULL);
g_assert (ctx->msg_data != NULL);
mm_base_modem_at_command (ctx->modem,
cmd,
10,