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:
@@ -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,12 +175,20 @@ mm_serial_parser_v1_parse (gpointer data,
|
||||
0, 0, NULL, NULL);
|
||||
if (found)
|
||||
remove_matches (parser->regex_ok, response);
|
||||
else
|
||||
}
|
||||
|
||||
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) {
|
||||
response_clean (response);
|
||||
return TRUE;
|
||||
@@ -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);
|
||||
|
102
src/mm-sms.c
102
src/mm-sms.c
@@ -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",
|
||||
*out_cmd = g_strdup_printf ("+CMG%c=\"%s\"",
|
||||
store_or_send ? 'S' : 'W',
|
||||
mm_sms_part_get_number (part),
|
||||
mm_sms_part_get_text (part));
|
||||
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",
|
||||
*out_cmd = g_strdup_printf ("+CMG%c=%d",
|
||||
store_or_send ? 'S' : 'W',
|
||||
pdulen - msgstart,
|
||||
hex);
|
||||
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,7 +487,7 @@ sms_store_finish (MMSms *self,
|
||||
}
|
||||
|
||||
static void
|
||||
store_ready (MMBaseModem *modem,
|
||||
store_msg_data_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
SmsStoreContext *ctx)
|
||||
{
|
||||
@@ -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,
|
||||
if (!sms_get_store_or_send_command ((MMSmsPart *)ctx->self->priv->parts->data,
|
||||
use_pdu_mode,
|
||||
FALSE,
|
||||
&error);
|
||||
if (!cmd) {
|
||||
&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,7 +636,7 @@ sms_send_finish (MMSms *self,
|
||||
}
|
||||
|
||||
static void
|
||||
send_generic_ready (MMBaseModem *modem,
|
||||
send_generic_msg_data_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
SmsSendContext *ctx)
|
||||
{
|
||||
@@ -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,
|
||||
if (!sms_get_store_or_send_command ((MMSmsPart *)ctx->self->priv->parts->data,
|
||||
use_pdu_mode,
|
||||
FALSE,
|
||||
&error);
|
||||
if (!cmd) {
|
||||
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,
|
||||
|
Reference in New Issue
Block a user