<div dir="ltr"><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">Great! Thanks</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">Carlo</div></div><div class="gmail_extra"><br><div class="gmail_quote">On 9 March 2016 at 14:46, Aleksander Morgado <span dir="ltr"><<a href="mailto:aleksander@aleksander.es" target="_blank">aleksander@aleksander.es</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On 09/03/16 11:27, <a href="mailto:c.lobrano@gmail.com">c.lobrano@gmail.com</a> wrote:<br>
> From: Carlo Lobrano <<a href="mailto:c.lobrano@gmail.com">c.lobrano@gmail.com</a>><br>
><br>
> * Add new async virtual method init_current_storages to<br>
>   MMIfaceModemMessaging<br>
> * Add logic of init_current_storages to MMBroadbandModem<br>
> * Add step "INIT_CURRENT_STORAGES" in MMIfaceModemMessaging<br>
>   initialization in order to load and store current SMS<br>
>   storages for mem1 and mem2.<br>
> * Add usage of current sms storage value for mem1 in place<br>
>   of an empty string parameter when the command AT+CPMS<br>
>   is used.<br>
><br>
<br>
</span>Rewrote a bit the commit message and pushed it to git master; thanks!<br>
<div><div class="h5"><br>
<br>
> ---<br>
>  src/mm-broadband-modem.c       | 92 +++++++++++++++++++++++++++++++++++++++++-<br>
>  src/mm-iface-modem-messaging.c | 37 +++++++++++++++++<br>
>  src/mm-iface-modem-messaging.h |  7 ++++<br>
>  src/mm-modem-helpers.c         | 76 ++++++++++++++++++++++++++++++++++<br>
>  src/mm-modem-helpers.h         | 10 +++++<br>
>  src/tests/test-modem-helpers.c | 35 ++++++++++++++++<br>
>  6 files changed, 256 insertions(+), 1 deletion(-)<br>
><br>
> diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c<br>
> index 6fc0663..e57195b 100644<br>
> --- a/src/mm-broadband-modem.c<br>
> +++ b/src/mm-broadband-modem.c<br>
> @@ -5242,6 +5242,77 @@ modem_messaging_load_supported_storages (MMIfaceModemMessaging *self,<br>
>  }<br>
><br>
>  /*****************************************************************************/<br>
> +/* Init current SMS storages (Messaging interface) */<br>
> +<br>
> +static gboolean<br>
> +modem_messaging_init_current_storages_finish (MMIfaceModemMessaging *_self,<br>
> +                                              GAsyncResult *res,<br>
> +                                              GError **error)<br>
> +{<br>
> +    return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);<br>
> +}<br>
> +<br>
> +static void<br>
> +cpms_query_ready (MMBroadbandModem *self,<br>
> +                  GAsyncResult *res,<br>
> +                  GSimpleAsyncResult *simple)<br>
> +{<br>
> +    const gchar *response;<br>
> +    GError *error = NULL;<br>
> +    MMSmsStorage mem1;<br>
> +    MMSmsStorage mem2;<br>
> +<br>
> +    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);<br>
> +    if (error) {<br>
> +        g_simple_async_result_take_error (simple, error);<br>
> +        g_simple_async_result_complete (simple);<br>
> +        g_object_unref (simple);<br>
> +        return;<br>
> +    }<br>
> +<br>
> +    /* Parse reply */<br>
> +    if (!mm_3gpp_parse_cpms_query_response (response,<br>
> +                                            &mem1,<br>
> +                                            &mem2,<br>
> +                                            &error)) {<br>
> +        g_simple_async_result_take_error (simple, error);<br>
> +    } else {<br>
> +        self->priv->current_sms_mem1_storage = mem1;<br>
> +        self->priv->current_sms_mem2_storage = mem2;<br>
> +<br>
> +        mm_dbg ("Current storages initialized:");<br>
> +        mm_dbg ("  mem1 (list/read/delete) storages: '%s'",<br>
> +                mm_common_build_sms_storages_string (&mem1, 1));<br>
> +        mm_dbg ("  mem2 (write/send) storages:       '%s'",<br>
> +                mm_common_build_sms_storages_string (&mem2, 1));<br>
> +    }<br>
> +<br>
> +    g_simple_async_result_complete (simple);<br>
> +    g_object_unref (simple);<br>
> +}<br>
> +<br>
> +static void<br>
> +modem_messaging_init_current_storages (MMIfaceModemMessaging *self,<br>
> +                                       GAsyncReadyCallback callback,<br>
> +                                       gpointer user_data)<br>
> +{<br>
> +    GSimpleAsyncResult *result;<br>
> +<br>
> +    result = g_simple_async_result_new (G_OBJECT (self),<br>
> +                                        callback,<br>
> +                                        user_data,<br>
> +                                        modem_messaging_init_current_storages);<br>
> +<br>
> +    /* Check support storages */<br>
> +    mm_base_modem_at_command (MM_BASE_MODEM (self),<br>
> +                              "+CPMS?",<br>
> +                              3,<br>
> +                              TRUE,<br>
> +                              (GAsyncReadyCallback)cpms_query_ready,<br>
> +                              result);<br>
> +}<br>
> +<br>
> +/*****************************************************************************/<br>
>  /* Lock/unlock SMS storage (Messaging interface implementation helper)<br>
>   *<br>
>   * The basic commands to work with SMS storages play with AT+CPMS and three<br>
> @@ -5382,6 +5453,15 @@ mm_broadband_modem_lock_sms_storages (MMBroadbandModem *self,<br>
>          self->priv->mem2_storage_locked = TRUE;<br>
>          self->priv->current_sms_mem2_storage = mem2;<br>
>          mem2_str = g_ascii_strup (mm_sms_storage_get_string (self->priv->current_sms_mem2_storage), -1);<br>
> +<br>
> +        if (mem1 == MM_SMS_STORAGE_UNKNOWN) {<br>
> +            /* Some modems may not support empty string parameters. Then if mem1 is<br>
> +             * UNKNOWN, we send again the already locked mem1 value in place of an<br>
> +             * empty string. This way we also avoid to confuse the environment of<br>
> +             * other async operation that have potentially locked mem1 previoulsy.<br>
> +             * */<br>
> +            mem1_str = g_ascii_strup (mm_sms_storage_get_string (self->priv->current_sms_mem1_storage), -1);<br>
> +        }<br>
>      }<br>
><br>
>      /* We don't touch 'mem3' here */<br>
> @@ -5446,6 +5526,7 @@ modem_messaging_set_default_storage (MMIfaceModemMessaging *_self,<br>
>      MMBroadbandModem *self = MM_BROADBAND_MODEM (_self);<br>
>      gchar *cmd;<br>
>      GSimpleAsyncResult *result;<br>
> +    gchar *mem1_str;<br>
>      gchar *mem_str;<br>
><br>
>      result = g_simple_async_result_new (G_OBJECT (self),<br>
> @@ -5456,14 +5537,21 @@ modem_messaging_set_default_storage (MMIfaceModemMessaging *_self,<br>
>      /* Set defaults as current */<br>
>      self->priv->current_sms_mem2_storage = storage;<br>
><br>
> +    /* We provide the current sms storage for mem1 if not UNKNOWN */<br>
> +    mem1_str = g_ascii_strup (mm_sms_storage_get_string (self->priv->current_sms_mem1_storage), -1);<br>
> +<br>
>      mem_str = g_ascii_strup (mm_sms_storage_get_string (storage), -1);<br>
> -    cmd = g_strdup_printf ("+CPMS=\"\",\"%s\",\"%s\"", mem_str, mem_str);<br>
> +    cmd = g_strdup_printf ("+CPMS=\"%s\",\"%s\",\"%s\"",<br>
> +                           mem1_str ? mem1_str : "",<br>
> +                           mem_str,<br>
> +                           mem_str);<br>
>      mm_base_modem_at_command (MM_BASE_MODEM (self),<br>
>                                cmd,<br>
>                                3,<br>
>                                FALSE,<br>
>                                (GAsyncReadyCallback)cpms_set_ready,<br>
>                                result);<br>
> +    g_free (mem1_str);<br>
>      g_free (mem_str);<br>
>      g_free (cmd);<br>
>  }<br>
> @@ -10390,6 +10478,8 @@ iface_modem_messaging_init (MMIfaceModemMessaging *iface)<br>
>      iface->cleanup_unsolicited_events = modem_messaging_cleanup_unsolicited_events;<br>
>      iface->cleanup_unsolicited_events_finish = modem_messaging_setup_cleanup_unsolicited_events_finish;<br>
>      iface->create_sms = modem_messaging_create_sms;<br>
> +    iface->init_current_storages = modem_messaging_init_current_storages;<br>
> +    iface->init_current_storages_finish = modem_messaging_init_current_storages_finish;<br>
>  }<br>
><br>
>  static void<br>
> diff --git a/src/mm-iface-modem-messaging.c b/src/mm-iface-modem-messaging.c<br>
> index d2ef6e8..0cff1f2 100644<br>
> --- a/src/mm-iface-modem-messaging.c<br>
> +++ b/src/mm-iface-modem-messaging.c<br>
> @@ -1057,6 +1057,7 @@ typedef enum {<br>
>      INITIALIZATION_STEP_CHECK_SUPPORT,<br>
>      INITIALIZATION_STEP_FAIL_IF_UNSUPPORTED,<br>
>      INITIALIZATION_STEP_LOAD_SUPPORTED_STORAGES,<br>
> +    INITIALIZATION_STEP_INIT_CURRENT_STORAGES,<br>
>      INITIALIZATION_STEP_LAST<br>
>  } InitializationStep;<br>
><br>
> @@ -1213,6 +1214,30 @@ check_support_ready (MMIfaceModemMessaging *self,<br>
>  }<br>
><br>
>  static void<br>
> +init_current_storages_ready (MMIfaceModemMessaging *self,<br>
> +                             GAsyncResult *res,<br>
> +                             InitializationContext *ctx)<br>
> +{<br>
> +    StorageContext *storage_ctx;<br>
> +    GError *error = NULL;<br>
> +<br>
> +    storage_ctx = get_storage_context (self);<br>
> +    if (!MM_IFACE_MODEM_MESSAGING_GET_INTERFACE (self)->init_current_storages_finish (<br>
> +            self,<br>
> +            res,<br>
> +            &error)) {<br>
> +        mm_dbg ("Couldn't initialize current storages: '%s'", error->message);<br>
> +        g_error_free (error);<br>
> +    } else {<br>
> +        mm_dbg ("Current storages initialized");<br>
> +    }<br>
> +<br>
> +    /* Go on to next step */<br>
> +    ctx->step++;<br>
> +    interface_initialization_step (ctx);<br>
> +}<br>
> +<br>
> +static void<br>
>  interface_initialization_step (InitializationContext *ctx)<br>
>  {<br>
>      /* Don't run new steps if we're cancelled */<br>
> @@ -1284,6 +1309,18 @@ interface_initialization_step (InitializationContext *ctx)<br>
>          /* Fall down to next step */<br>
>          ctx->step++;<br>
><br>
> +    case INITIALIZATION_STEP_INIT_CURRENT_STORAGES:<br>
> +        if (MM_IFACE_MODEM_MESSAGING_GET_INTERFACE (ctx->self)->init_current_storages &&<br>
> +            MM_IFACE_MODEM_MESSAGING_GET_INTERFACE (ctx->self)->init_current_storages_finish) {<br>
> +            MM_IFACE_MODEM_MESSAGING_GET_INTERFACE (ctx->self)->init_current_storages (<br>
> +                ctx->self,<br>
> +                (GAsyncReadyCallback)init_current_storages_ready,<br>
> +                ctx);<br>
> +            return;<br>
> +        }<br>
> +        /* Fall down to next step */<br>
> +        ctx->step++;<br>
> +<br>
>      case INITIALIZATION_STEP_LAST:<br>
>          /* We are done without errors! */<br>
><br>
> diff --git a/src/mm-iface-modem-messaging.h b/src/mm-iface-modem-messaging.h<br>
> index c27e100..57fa452 100644<br>
> --- a/src/mm-iface-modem-messaging.h<br>
> +++ b/src/mm-iface-modem-messaging.h<br>
> @@ -62,6 +62,13 @@ struct _MMIfaceModemMessaging {<br>
>                                                  GArray **mem2,<br>
>                                                  GArray **mem3,<br>
>                                                  GError **error);<br>
> +    /* Initializes the state of the storages */<br>
> +    void (* init_current_storages) (MMIfaceModemMessaging *self,<br>
> +                                    GAsyncReadyCallback callback,<br>
> +                                    gpointer user_data);<br>
> +    gboolean (*init_current_storages_finish) (MMIfaceModemMessaging *self,<br>
> +                                              GAsyncResult *res,<br>
> +                                              GError **error);<br>
><br>
>      /* Set default storage (async) */<br>
>      void (* set_default_storage) (MMIfaceModemMessaging *self,<br>
> diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c<br>
> index 58394ee..74e5546 100644<br>
> --- a/src/mm-modem-helpers.c<br>
> +++ b/src/mm-modem-helpers.c<br>
> @@ -1507,6 +1507,82 @@ mm_3gpp_parse_cpms_test_response (const gchar *reply,<br>
>      return FALSE;<br>
>  }<br>
><br>
> +/**********************************************************************<br>
> + * AT+CPMS?<br>
> + * +CPMS: <memr>,<usedr>,<totalr>,<memw>,<usedw>,<totalw>, <mems>,<useds>,<totals><br>
> + */<br>
> +<br>
> +#define CPMS_QUERY_REGEX "\\+CPMS:\\s*\"(?P<memr>.*)\",[0-9]+,[0-9]+,\"(?P<memw>.*)\",[0-9]+,[0-9]+,\"(?P<mems>.*)\",[0-9]+,[0-9]"<br>
> +<br>
> +gboolean<br>
> +mm_3gpp_parse_cpms_query_response (const gchar *reply,<br>
> +                                   MMSmsStorage *memr,<br>
> +                                   MMSmsStorage *memw,<br>
> +                                   GError **error)<br>
> +{<br>
> +    GRegex *r = NULL;<br>
> +    gboolean ret = FALSE;<br>
> +    GMatchInfo *match_info = NULL;<br>
> +<br>
> +    r = g_regex_new (CPMS_QUERY_REGEX, G_REGEX_RAW, 0, NULL);<br>
> +<br>
> +    g_assert(r);<br>
> +<br>
> +    if (!g_regex_match (r, reply, 0, &match_info)) {<br>
> +        g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,<br>
> +                     "Could not parse CPMS query reponse '%s'", reply);<br>
> +        goto end;<br>
> +    }<br>
> +<br>
> +    if (!g_match_info_matches(match_info)) {<br>
> +        g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,<br>
> +                     "Could not find matches in CPMS query reply '%s'", reply);<br>
> +        goto end;<br>
> +    }<br>
> +<br>
> +    if (!mm_3gpp_get_cpms_storage_match (match_info, "memr", memr, error)) {<br>
> +        goto end;<br>
> +    }<br>
> +<br>
> +    if (!mm_3gpp_get_cpms_storage_match (match_info, "memw", memw, error)) {<br>
> +        goto end;<br>
> +    }<br>
> +<br>
> +    ret = TRUE;<br>
> +<br>
> +end:<br>
> +    if (r != NULL)<br>
> +        g_regex_unref (r);<br>
> +<br>
> +    if (match_info != NULL)<br>
> +        g_match_info_free (match_info);<br>
> +<br>
> +    return ret;<br>
> +}<br>
> +<br>
> +gboolean<br>
> +mm_3gpp_get_cpms_storage_match (GMatchInfo *match_info,<br>
> +                                const gchar *match_name,<br>
> +                                MMSmsStorage *storage,<br>
> +                                GError **error)<br>
> +{<br>
> +    gboolean ret = TRUE;<br>
> +    gchar *str = NULL;<br>
> +<br>
> +    str = g_match_info_fetch_named(match_info, match_name);<br>
> +    if (str == NULL || str[0] == '\0') {<br>
> +        g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,<br>
> +                     "Could not find '%s' from CPMS reply", match_name);<br>
> +        ret = FALSE;<br>
> +    } else {<br>
> +        *storage = storage_from_str (str);<br>
> +    }<br>
> +<br>
> +    g_free (str);<br>
> +<br>
> +    return ret;<br>
> +}<br>
> +<br>
>  /*************************************************************************/<br>
><br>
>  gboolean<br>
> diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h<br>
> index 975a493..476b315 100644<br>
> --- a/src/mm-modem-helpers.h<br>
> +++ b/src/mm-modem-helpers.h<br>
> @@ -158,6 +158,16 @@ gboolean mm_3gpp_parse_cpms_test_response (const gchar *reply,<br>
>                                             GArray **mem2,<br>
>                                             GArray **mem3);<br>
><br>
> +/* AT+CPMS? (Current SMS storage) response parser */<br>
> +gboolean mm_3gpp_parse_cpms_query_response (const gchar *reply,<br>
> +                                            MMSmsStorage *mem1,<br>
> +                                            MMSmsStorage *mem2,<br>
> +                                            GError** error);<br>
> +gboolean mm_3gpp_get_cpms_storage_match (GMatchInfo *match_info,<br>
> +                                         const gchar *match_name,<br>
> +                                         MMSmsStorage *storage,<br>
> +                                         GError **error);<br>
> +<br>
>  /* AT+CSCS=? (Supported charsets) response parser */<br>
>  gboolean mm_3gpp_parse_cscs_test_response (const gchar *reply,<br>
>                                             MMModemCharset *out_charsets);<br>
> diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c<br>
> index db84f01..ddd25af 100644<br>
> --- a/src/tests/test-modem-helpers.c<br>
> +++ b/src/tests/test-modem-helpers.c<br>
> @@ -2070,6 +2070,40 @@ test_cpms_response_empty_fields (void *f, gpointer d)<br>
>      g_array_unref (mem3);<br>
>  }<br>
><br>
> +typedef struct {<br>
> +    const gchar *query;<br>
> +    MMSmsStorage mem1_want;<br>
> +    MMSmsStorage mem2_want;<br>
> +} CpmsQueryTest;<br>
> +<br>
> +CpmsQueryTest cpms_query_test[] = {<br>
> +    {"+CPMS: \"ME\",1,100,\"MT\",5,100,\"TA\",1,100", 2, 3},<br>
> +    {"+CPMS: \"SM\",100,100,\"SR\",5,10,\"TA\",1,100", 1, 4},<br>
> +    {"+CPMS: \"XX\",100,100,\"BM\",5,10,\"TA\",1,100", 0, 5},<br>
> +    {"+CPMS: \"XX\",100,100,\"YY\",5,10,\"TA\",1,100", 0, 0},<br>
> +    {NULL, 0, 0}<br>
> +};<br>
> +<br>
> +static void<br>
> +test_cpms_query_response (void *f, gpointer d) {<br>
> +    MMSmsStorage mem1;<br>
> +    MMSmsStorage mem2;<br>
> +    gboolean ret;<br>
> +    GError *error = NULL;<br>
> +    int i;<br>
> +<br>
> +    for (i = 0; cpms_query_test[i].query != NULL; i++){<br>
> +        ret = mm_3gpp_parse_cpms_query_response (cpms_query_test[i].query,<br>
> +                                                 &mem1,<br>
> +                                                 &mem2,<br>
> +                                                 &error);<br>
> +        g_assert(ret);<br>
> +        g_assert_no_error (error);<br>
> +        g_assert_cmpuint (cpms_query_test[i].mem1_want, ==, mem1);<br>
> +        g_assert_cmpuint (cpms_query_test[i].mem2_want, ==, mem2);<br>
> +    }<br>
> +}<br>
> +<br>
>  /*****************************************************************************/<br>
>  /* Test CNUM responses */<br>
><br>
> @@ -2821,6 +2855,7 @@ int main (int argc, char **argv)<br>
>      g_test_suite_add (suite, TESTCASE (test_cpms_response_mixed,        NULL));<br>
>      g_test_suite_add (suite, TESTCASE (test_cpms_response_mixed_spaces, NULL));<br>
>      g_test_suite_add (suite, TESTCASE (test_cpms_response_empty_fields, NULL));<br>
> +    g_test_suite_add (suite, TESTCASE (test_cpms_query_response,        NULL));<br>
><br>
>      g_test_suite_add (suite, TESTCASE (test_cgdcont_test_response_single, NULL));<br>
>      g_test_suite_add (suite, TESTCASE (test_cgdcont_test_response_multiple, NULL));<br>
><br>
<br>
<br>
--<br>
</div></div>Aleksander<br>
<a href="https://aleksander.es" rel="noreferrer" target="_blank">https://aleksander.es</a><br>
</blockquote></div><br></div>