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:

committed by
Aleksander Morgado

parent
7c2d5b1aa3
commit
be317e8b80
@@ -5241,6 +5241,77 @@ modem_messaging_load_supported_storages (MMIfaceModemMessaging *self,
|
|||||||
result);
|
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)
|
/* 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->mem2_storage_locked = TRUE;
|
||||||
self->priv->current_sms_mem2_storage = mem2;
|
self->priv->current_sms_mem2_storage = mem2;
|
||||||
mem2_str = g_ascii_strup (mm_sms_storage_get_string (self->priv->current_sms_mem2_storage), -1);
|
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 */
|
/* We don't touch 'mem3' here */
|
||||||
@@ -5446,6 +5526,7 @@ modem_messaging_set_default_storage (MMIfaceModemMessaging *_self,
|
|||||||
MMBroadbandModem *self = MM_BROADBAND_MODEM (_self);
|
MMBroadbandModem *self = MM_BROADBAND_MODEM (_self);
|
||||||
gchar *cmd;
|
gchar *cmd;
|
||||||
GSimpleAsyncResult *result;
|
GSimpleAsyncResult *result;
|
||||||
|
gchar *mem1_str;
|
||||||
gchar *mem_str;
|
gchar *mem_str;
|
||||||
|
|
||||||
result = g_simple_async_result_new (G_OBJECT (self),
|
result = g_simple_async_result_new (G_OBJECT (self),
|
||||||
@@ -5456,14 +5537,21 @@ modem_messaging_set_default_storage (MMIfaceModemMessaging *_self,
|
|||||||
/* Set defaults as current */
|
/* Set defaults as current */
|
||||||
self->priv->current_sms_mem2_storage = storage;
|
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);
|
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),
|
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||||
cmd,
|
cmd,
|
||||||
3,
|
3,
|
||||||
FALSE,
|
FALSE,
|
||||||
(GAsyncReadyCallback)cpms_set_ready,
|
(GAsyncReadyCallback)cpms_set_ready,
|
||||||
result);
|
result);
|
||||||
|
g_free (mem1_str);
|
||||||
g_free (mem_str);
|
g_free (mem_str);
|
||||||
g_free (cmd);
|
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 = modem_messaging_cleanup_unsolicited_events;
|
||||||
iface->cleanup_unsolicited_events_finish = modem_messaging_setup_cleanup_unsolicited_events_finish;
|
iface->cleanup_unsolicited_events_finish = modem_messaging_setup_cleanup_unsolicited_events_finish;
|
||||||
iface->create_sms = modem_messaging_create_sms;
|
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
|
static void
|
||||||
|
@@ -1057,6 +1057,7 @@ typedef enum {
|
|||||||
INITIALIZATION_STEP_CHECK_SUPPORT,
|
INITIALIZATION_STEP_CHECK_SUPPORT,
|
||||||
INITIALIZATION_STEP_FAIL_IF_UNSUPPORTED,
|
INITIALIZATION_STEP_FAIL_IF_UNSUPPORTED,
|
||||||
INITIALIZATION_STEP_LOAD_SUPPORTED_STORAGES,
|
INITIALIZATION_STEP_LOAD_SUPPORTED_STORAGES,
|
||||||
|
INITIALIZATION_STEP_INIT_CURRENT_STORAGES,
|
||||||
INITIALIZATION_STEP_LAST
|
INITIALIZATION_STEP_LAST
|
||||||
} InitializationStep;
|
} InitializationStep;
|
||||||
|
|
||||||
@@ -1212,6 +1213,30 @@ check_support_ready (MMIfaceModemMessaging *self,
|
|||||||
interface_initialization_step (ctx);
|
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
|
static void
|
||||||
interface_initialization_step (InitializationContext *ctx)
|
interface_initialization_step (InitializationContext *ctx)
|
||||||
{
|
{
|
||||||
@@ -1284,6 +1309,18 @@ interface_initialization_step (InitializationContext *ctx)
|
|||||||
/* Fall down to next step */
|
/* Fall down to next step */
|
||||||
ctx->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:
|
case INITIALIZATION_STEP_LAST:
|
||||||
/* We are done without errors! */
|
/* We are done without errors! */
|
||||||
|
|
||||||
|
@@ -62,6 +62,13 @@ struct _MMIfaceModemMessaging {
|
|||||||
GArray **mem2,
|
GArray **mem2,
|
||||||
GArray **mem3,
|
GArray **mem3,
|
||||||
GError **error);
|
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) */
|
/* Set default storage (async) */
|
||||||
void (* set_default_storage) (MMIfaceModemMessaging *self,
|
void (* set_default_storage) (MMIfaceModemMessaging *self,
|
||||||
|
@@ -1507,6 +1507,82 @@ mm_3gpp_parse_cpms_test_response (const gchar *reply,
|
|||||||
return FALSE;
|
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
|
gboolean
|
||||||
|
@@ -158,6 +158,16 @@ gboolean mm_3gpp_parse_cpms_test_response (const gchar *reply,
|
|||||||
GArray **mem2,
|
GArray **mem2,
|
||||||
GArray **mem3);
|
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 */
|
/* AT+CSCS=? (Supported charsets) response parser */
|
||||||
gboolean mm_3gpp_parse_cscs_test_response (const gchar *reply,
|
gboolean mm_3gpp_parse_cscs_test_response (const gchar *reply,
|
||||||
MMModemCharset *out_charsets);
|
MMModemCharset *out_charsets);
|
||||||
|
@@ -2070,6 +2070,40 @@ test_cpms_response_empty_fields (void *f, gpointer d)
|
|||||||
g_array_unref (mem3);
|
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 */
|
/* 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, NULL));
|
||||||
g_test_suite_add (suite, TESTCASE (test_cpms_response_mixed_spaces, 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_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_single, NULL));
|
||||||
g_test_suite_add (suite, TESTCASE (test_cgdcont_test_response_multiple, NULL));
|
g_test_suite_add (suite, TESTCASE (test_cgdcont_test_response_multiple, NULL));
|
||||||
|
Reference in New Issue
Block a user