broadband-modem: fix +CPMS empty parameter support

* Add new async virtual method init_current_storages to
  MMIfaceModemMessaging
* Add logic of init_current_storages to MMBroadbandModem
* Add step "INIT_CURRENT_STORAGES" in MMIfaceModemMessaging
  initialization in order to load and store current SMS
  storages for mem1 and mem2.
* Add usage of current sms storage value for mem1 in place
  of an empty string parameter when the command AT+CPMS
  is used.

https://bugs.freedesktop.org/show_bug.cgi?id=93135
This commit is contained in:
Carlo Lobrano
2016-03-09 11:27:43 +01:00
committed by Aleksander Morgado
parent 7c2d5b1aa3
commit be317e8b80
6 changed files with 256 additions and 1 deletions

View File

@@ -5241,6 +5241,77 @@ modem_messaging_load_supported_storages (MMIfaceModemMessaging *self,
result);
}
/*****************************************************************************/
/* Init current SMS storages (Messaging interface) */
static gboolean
modem_messaging_init_current_storages_finish (MMIfaceModemMessaging *_self,
GAsyncResult *res,
GError **error)
{
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
}
static void
cpms_query_ready (MMBroadbandModem *self,
GAsyncResult *res,
GSimpleAsyncResult *simple)
{
const gchar *response;
GError *error = NULL;
MMSmsStorage mem1;
MMSmsStorage mem2;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
if (error) {
g_simple_async_result_take_error (simple, error);
g_simple_async_result_complete (simple);
g_object_unref (simple);
return;
}
/* Parse reply */
if (!mm_3gpp_parse_cpms_query_response (response,
&mem1,
&mem2,
&error)) {
g_simple_async_result_take_error (simple, error);
} else {
self->priv->current_sms_mem1_storage = mem1;
self->priv->current_sms_mem2_storage = mem2;
mm_dbg ("Current storages initialized:");
mm_dbg (" mem1 (list/read/delete) storages: '%s'",
mm_common_build_sms_storages_string (&mem1, 1));
mm_dbg (" mem2 (write/send) storages: '%s'",
mm_common_build_sms_storages_string (&mem2, 1));
}
g_simple_async_result_complete (simple);
g_object_unref (simple);
}
static void
modem_messaging_init_current_storages (MMIfaceModemMessaging *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *result;
result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
modem_messaging_init_current_storages);
/* Check support storages */
mm_base_modem_at_command (MM_BASE_MODEM (self),
"+CPMS?",
3,
TRUE,
(GAsyncReadyCallback)cpms_query_ready,
result);
}
/*****************************************************************************/
/* Lock/unlock SMS storage (Messaging interface implementation helper)
*
@@ -5382,6 +5453,15 @@ mm_broadband_modem_lock_sms_storages (MMBroadbandModem *self,
self->priv->mem2_storage_locked = TRUE;
self->priv->current_sms_mem2_storage = mem2;
mem2_str = g_ascii_strup (mm_sms_storage_get_string (self->priv->current_sms_mem2_storage), -1);
if (mem1 == MM_SMS_STORAGE_UNKNOWN) {
/* Some modems may not support empty string parameters. Then if mem1 is
* UNKNOWN, we send again the already locked mem1 value in place of an
* empty string. This way we also avoid to confuse the environment of
* other async operation that have potentially locked mem1 previoulsy.
* */
mem1_str = g_ascii_strup (mm_sms_storage_get_string (self->priv->current_sms_mem1_storage), -1);
}
}
/* We don't touch 'mem3' here */
@@ -5446,6 +5526,7 @@ modem_messaging_set_default_storage (MMIfaceModemMessaging *_self,
MMBroadbandModem *self = MM_BROADBAND_MODEM (_self);
gchar *cmd;
GSimpleAsyncResult *result;
gchar *mem1_str;
gchar *mem_str;
result = g_simple_async_result_new (G_OBJECT (self),
@@ -5456,14 +5537,21 @@ modem_messaging_set_default_storage (MMIfaceModemMessaging *_self,
/* Set defaults as current */
self->priv->current_sms_mem2_storage = storage;
/* We provide the current sms storage for mem1 if not UNKNOWN */
mem1_str = g_ascii_strup (mm_sms_storage_get_string (self->priv->current_sms_mem1_storage), -1);
mem_str = g_ascii_strup (mm_sms_storage_get_string (storage), -1);
cmd = g_strdup_printf ("+CPMS=\"\",\"%s\",\"%s\"", mem_str, mem_str);
cmd = g_strdup_printf ("+CPMS=\"%s\",\"%s\",\"%s\"",
mem1_str ? mem1_str : "",
mem_str,
mem_str);
mm_base_modem_at_command (MM_BASE_MODEM (self),
cmd,
3,
FALSE,
(GAsyncReadyCallback)cpms_set_ready,
result);
g_free (mem1_str);
g_free (mem_str);
g_free (cmd);
}
@@ -10390,6 +10478,8 @@ iface_modem_messaging_init (MMIfaceModemMessaging *iface)
iface->cleanup_unsolicited_events = modem_messaging_cleanup_unsolicited_events;
iface->cleanup_unsolicited_events_finish = modem_messaging_setup_cleanup_unsolicited_events_finish;
iface->create_sms = modem_messaging_create_sms;
iface->init_current_storages = modem_messaging_init_current_storages;
iface->init_current_storages_finish = modem_messaging_init_current_storages_finish;
}
static void

View File

@@ -1057,6 +1057,7 @@ typedef enum {
INITIALIZATION_STEP_CHECK_SUPPORT,
INITIALIZATION_STEP_FAIL_IF_UNSUPPORTED,
INITIALIZATION_STEP_LOAD_SUPPORTED_STORAGES,
INITIALIZATION_STEP_INIT_CURRENT_STORAGES,
INITIALIZATION_STEP_LAST
} InitializationStep;
@@ -1212,6 +1213,30 @@ check_support_ready (MMIfaceModemMessaging *self,
interface_initialization_step (ctx);
}
static void
init_current_storages_ready (MMIfaceModemMessaging *self,
GAsyncResult *res,
InitializationContext *ctx)
{
StorageContext *storage_ctx;
GError *error = NULL;
storage_ctx = get_storage_context (self);
if (!MM_IFACE_MODEM_MESSAGING_GET_INTERFACE (self)->init_current_storages_finish (
self,
res,
&error)) {
mm_dbg ("Couldn't initialize current storages: '%s'", error->message);
g_error_free (error);
} else {
mm_dbg ("Current storages initialized");
}
/* Go on to next step */
ctx->step++;
interface_initialization_step (ctx);
}
static void
interface_initialization_step (InitializationContext *ctx)
{
@@ -1284,6 +1309,18 @@ interface_initialization_step (InitializationContext *ctx)
/* Fall down to next step */
ctx->step++;
case INITIALIZATION_STEP_INIT_CURRENT_STORAGES:
if (MM_IFACE_MODEM_MESSAGING_GET_INTERFACE (ctx->self)->init_current_storages &&
MM_IFACE_MODEM_MESSAGING_GET_INTERFACE (ctx->self)->init_current_storages_finish) {
MM_IFACE_MODEM_MESSAGING_GET_INTERFACE (ctx->self)->init_current_storages (
ctx->self,
(GAsyncReadyCallback)init_current_storages_ready,
ctx);
return;
}
/* Fall down to next step */
ctx->step++;
case INITIALIZATION_STEP_LAST:
/* We are done without errors! */

View File

@@ -62,6 +62,13 @@ struct _MMIfaceModemMessaging {
GArray **mem2,
GArray **mem3,
GError **error);
/* Initializes the state of the storages */
void (* init_current_storages) (MMIfaceModemMessaging *self,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean (*init_current_storages_finish) (MMIfaceModemMessaging *self,
GAsyncResult *res,
GError **error);
/* Set default storage (async) */
void (* set_default_storage) (MMIfaceModemMessaging *self,

View File

@@ -1507,6 +1507,82 @@ mm_3gpp_parse_cpms_test_response (const gchar *reply,
return FALSE;
}
/**********************************************************************
* AT+CPMS?
* +CPMS: <memr>,<usedr>,<totalr>,<memw>,<usedw>,<totalw>, <mems>,<useds>,<totals>
*/
#define CPMS_QUERY_REGEX "\\+CPMS:\\s*\"(?P<memr>.*)\",[0-9]+,[0-9]+,\"(?P<memw>.*)\",[0-9]+,[0-9]+,\"(?P<mems>.*)\",[0-9]+,[0-9]"
gboolean
mm_3gpp_parse_cpms_query_response (const gchar *reply,
MMSmsStorage *memr,
MMSmsStorage *memw,
GError **error)
{
GRegex *r = NULL;
gboolean ret = FALSE;
GMatchInfo *match_info = NULL;
r = g_regex_new (CPMS_QUERY_REGEX, G_REGEX_RAW, 0, NULL);
g_assert(r);
if (!g_regex_match (r, reply, 0, &match_info)) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"Could not parse CPMS query reponse '%s'", reply);
goto end;
}
if (!g_match_info_matches(match_info)) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"Could not find matches in CPMS query reply '%s'", reply);
goto end;
}
if (!mm_3gpp_get_cpms_storage_match (match_info, "memr", memr, error)) {
goto end;
}
if (!mm_3gpp_get_cpms_storage_match (match_info, "memw", memw, error)) {
goto end;
}
ret = TRUE;
end:
if (r != NULL)
g_regex_unref (r);
if (match_info != NULL)
g_match_info_free (match_info);
return ret;
}
gboolean
mm_3gpp_get_cpms_storage_match (GMatchInfo *match_info,
const gchar *match_name,
MMSmsStorage *storage,
GError **error)
{
gboolean ret = TRUE;
gchar *str = NULL;
str = g_match_info_fetch_named(match_info, match_name);
if (str == NULL || str[0] == '\0') {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"Could not find '%s' from CPMS reply", match_name);
ret = FALSE;
} else {
*storage = storage_from_str (str);
}
g_free (str);
return ret;
}
/*************************************************************************/
gboolean

View File

@@ -158,6 +158,16 @@ gboolean mm_3gpp_parse_cpms_test_response (const gchar *reply,
GArray **mem2,
GArray **mem3);
/* AT+CPMS? (Current SMS storage) response parser */
gboolean mm_3gpp_parse_cpms_query_response (const gchar *reply,
MMSmsStorage *mem1,
MMSmsStorage *mem2,
GError** error);
gboolean mm_3gpp_get_cpms_storage_match (GMatchInfo *match_info,
const gchar *match_name,
MMSmsStorage *storage,
GError **error);
/* AT+CSCS=? (Supported charsets) response parser */
gboolean mm_3gpp_parse_cscs_test_response (const gchar *reply,
MMModemCharset *out_charsets);

View File

@@ -2070,6 +2070,40 @@ test_cpms_response_empty_fields (void *f, gpointer d)
g_array_unref (mem3);
}
typedef struct {
const gchar *query;
MMSmsStorage mem1_want;
MMSmsStorage mem2_want;
} CpmsQueryTest;
CpmsQueryTest cpms_query_test[] = {
{"+CPMS: \"ME\",1,100,\"MT\",5,100,\"TA\",1,100", 2, 3},
{"+CPMS: \"SM\",100,100,\"SR\",5,10,\"TA\",1,100", 1, 4},
{"+CPMS: \"XX\",100,100,\"BM\",5,10,\"TA\",1,100", 0, 5},
{"+CPMS: \"XX\",100,100,\"YY\",5,10,\"TA\",1,100", 0, 0},
{NULL, 0, 0}
};
static void
test_cpms_query_response (void *f, gpointer d) {
MMSmsStorage mem1;
MMSmsStorage mem2;
gboolean ret;
GError *error = NULL;
int i;
for (i = 0; cpms_query_test[i].query != NULL; i++){
ret = mm_3gpp_parse_cpms_query_response (cpms_query_test[i].query,
&mem1,
&mem2,
&error);
g_assert(ret);
g_assert_no_error (error);
g_assert_cmpuint (cpms_query_test[i].mem1_want, ==, mem1);
g_assert_cmpuint (cpms_query_test[i].mem2_want, ==, mem2);
}
}
/*****************************************************************************/
/* Test CNUM responses */
@@ -2821,6 +2855,7 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_cpms_response_mixed, NULL));
g_test_suite_add (suite, TESTCASE (test_cpms_response_mixed_spaces, NULL));
g_test_suite_add (suite, TESTCASE (test_cpms_response_empty_fields, NULL));
g_test_suite_add (suite, TESTCASE (test_cpms_query_response, NULL));
g_test_suite_add (suite, TESTCASE (test_cgdcont_test_response_single, NULL));
g_test_suite_add (suite, TESTCASE (test_cgdcont_test_response_multiple, NULL));