static void
cnti_set_ready (MMBaseModem *self,
                GAsyncResult *res,
                GSimpleAsyncResult *simple)
{
    GError *error = NULL;
    const gchar *response;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
    if (!response)
        g_simple_async_result_take_error (simple, error);
    else {
        MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
        const gchar *p;

        p = mm_strip_tag (response, "*CNTI:");
        p = strchr (p, ',');
        if (p)
            act = mm_string_to_access_tech (p + 1);

        if (act == MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN)
            g_simple_async_result_set_error (
                simple,
                MM_CORE_ERROR,
                MM_CORE_ERROR_FAILED,
                "Couldn't parse access technologies result: '%s'",
                response);
        else
            g_simple_async_result_set_op_res_gpointer (simple, GUINT_TO_POINTER (act), NULL);
    }

    g_simple_async_result_complete (simple);
    g_object_unref (simple);
}
static gboolean
messaging_enable_unsolicited_events_finish (MMIfaceModemMessaging *self,
                                            GAsyncResult *res,
                                            GError **error)
{
    return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
}
static gboolean
load_access_technologies_finish (MMIfaceModem *self,
                                 GAsyncResult *res,
                                 MMModemAccessTechnology *access_technologies,
                                 guint *mask,
                                 GError **error)
{
    const gchar *p;
    const gchar *response;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
    if (!response)
        return FALSE;

    p = mm_strip_tag (response, "*CNTI:");
    p = strchr (p, ',');
    if (p) {
        /* We are reporting ALL 3GPP access technologies here */
        *access_technologies = mm_string_to_access_tech (p + 1);
        *mask = MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK;
        return TRUE;
    }

    g_set_error (error,
                 MM_CORE_ERROR,
                 MM_CORE_ERROR_FAILED,
                 "Couldn't parse access technologies result: '%s'",
                 response);
    return FALSE;
}
static void
connect_3gpp_qmiconnect_ready (MMBaseModem *modem,
                               GAsyncResult *res,
                               DetailedConnectContext *ctx)
{
    const gchar *result;
    GError *error = NULL;

    result = mm_base_modem_at_command_finish (MM_BASE_MODEM (modem),
                                              res,
                                              &error);
    if (!result) {
        mm_warn ("QMI connection failed: %s", error->message);
        g_simple_async_result_take_error (ctx->result, error);
        detailed_connect_context_complete_and_free (ctx);
        return;
    }

    /*
     * The connection takes a bit of time to set up, but there's no
     * asynchronous notification from the modem when this has
     * happened. Instead, we need to poll the modem to see if it's
     * ready.
     */
    g_timeout_add_seconds(1, (GSourceFunc)connect_3gpp_qmistatus, ctx);
}
static void
cgclass_update_ready (MMBaseModem *self,
                      GAsyncResult *res,
                      SetAllowedModesContext *ctx)
{
    GError *error = NULL;

    mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
    if (error) {
        /* Let the error be critical. */
        g_simple_async_result_take_error (ctx->result, error);
        set_allowed_modes_context_complete_and_free (ctx);
        return;
    }

    if (!ctx->wwsm_command) {
        g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
        set_allowed_modes_context_complete_and_free (ctx);
        return;
    }

    mm_base_modem_at_command (MM_BASE_MODEM (self),
                              ctx->wwsm_command,
                              3,
                              FALSE,
                              (GAsyncReadyCallback)wwsm_update_ready,
                              ctx);
}
static gboolean
modem_power_down_finish (MMIfaceModem *self,
                         GAsyncResult *res,
                         GError **error)
{
    return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
}
static guint
load_signal_quality_finish (MMIfaceModem *self,
                            GAsyncResult *res,
                            GError **error)
{
    gint quality = 0;
    const gchar *result;

    result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
    if (!result)
        return 0;

    /* Skip possible whitespaces after '+CSQF:' and before the response */
    result = mm_strip_tag (result, "+CSQF:");
    while (*result == ' ')
        result++;

    if (sscanf (result, "%d", &quality))
        /* Normalize the quality. <rssi> is NOT given in dBs,
         * given as a relative value between 0 and 5 */
        quality = CLAMP (quality, 0, 5) * 100 / 5;
    else
        g_set_error (error,
                     MM_CORE_ERROR,
                     MM_CORE_ERROR_FAILED,
                     "Could not parse signal quality results");

    return quality;
}
static void
cnti_set_ready (MMBaseModem *self,
                GAsyncResult *res,
                GSimpleAsyncResult *simple)
{
    GError *error = NULL;
    const gchar *response;
    const gchar *p;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
    if (!response) {
        g_simple_async_result_take_error (simple, error);
        g_simple_async_result_complete (simple);
        g_object_unref (simple);
        return;
    }

    p = mm_strip_tag (response, "$CNTI:");
    p = strchr (p, ',');
    if (!p) {
        error = g_error_new (MM_CORE_ERROR,
                             MM_CORE_ERROR_FAILED,
                             "Couldn't parse $CNTI result '%s'",
                             response);
        g_simple_async_result_take_error (simple, error);
        g_simple_async_result_complete (simple);
        g_object_unref (simple);
        return;
    }

    snapshot_result_complete_simple (simple,
                                     mm_string_to_access_tech (p),
                                     MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK);
    g_object_unref (simple);
}
static gboolean
setup_flow_control_finish (MMIfaceModem *self,
                           GAsyncResult *res,
                           GError **error)
{
    return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
}
static void
ossys_query_ready (MMBaseModem *self,
                   GAsyncResult *res,
                   AccessTechnologiesContext *ctx)
{
    const gchar *response;

    /* If for some reason the OSSYS request failed, still try to check
     * explicit 2G/3G mode with OCTI and OWCTI; maybe we'll get something.
     */
    response = mm_base_modem_at_command_finish (self, res, NULL);
    /* Response is _OSSYS: <n>,<act> so we must skip the <n> */
    if (response &&
        parse_ossys_response (response, &ctx->access_technology)) {
        /* If the OSSYS response indicated a generic access tech type
         * then only check for more specific access tech of that type.
         */
        if (ctx->access_technology == MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
            ctx->check_3g = FALSE;
        else if (ctx->access_technology == MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
            ctx->check_2g = FALSE;
    }

    /* Go on to next step */
    ctx->step++;
    load_access_technologies_step (ctx);
}
static void
emrdy_ready (MMBaseModem *self,
             GAsyncResult *res,
             EnablingModemInitContext *ctx)
{
    GError *error = NULL;

    /* EMRDY unsolicited response might have happened between the command
     * submission and the response.  This was seen once:
     *
     * (ttyACM0): --> 'AT*EMRDY?<CR>'
     * (ttyACM0): <-- 'T*EMRD<CR><LF>*EMRDY: 1<CR><LF>Y?'
     *
     * So suppress the warning if the unsolicited handler handled the response
     * before we get here.
     */
    if (!mm_base_modem_at_command_finish (self, res, &error)) {
        if (g_error_matches (error,
                             MM_SERIAL_ERROR,
                             MM_SERIAL_ERROR_RESPONSE_TIMEOUT))
            mm_warn ("timed out waiting for EMRDY response.");
        else
            ctx->self->priv->have_emrdy = TRUE;
        g_error_free (error);
    }

    run_enabling_init_sequence (ctx);
}
static gboolean
modem_time_check_support_finish (MMIfaceModemTime *self,
                                 GAsyncResult *res,
                                 GError **error)
{
    return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
}
static gboolean
load_current_modes_finish (MMIfaceModem *self,
                           GAsyncResult *res,
                           MMModemMode *allowed,
                           MMModemMode *preferred,
                           GError **error)
{
    const gchar *response;
    const gchar *str;
    gint a, b;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
    if (!response)
        return FALSE;

    str = mm_strip_tag (response, "_OPSYS:");

    if (!sscanf (str, "%d,%d", &a, &b)) {
        g_set_error (error,
                     MM_CORE_ERROR,
                     MM_CORE_ERROR_FAILED,
                     "Couldn't parse OPSYS response: '%s'",
                     response);
        return FALSE;
    }

    switch (a) {
    case 0:
        *allowed = MM_MODEM_MODE_2G;
        *preferred = MM_MODEM_MODE_NONE;
        return TRUE;
    case 1:
        *allowed = MM_MODEM_MODE_3G;
        *preferred = MM_MODEM_MODE_NONE;
        return TRUE;
    case 2:
        *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
        *preferred = MM_MODEM_MODE_2G;
        return TRUE;
    case 3:
        *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
        *preferred = MM_MODEM_MODE_3G;
        return TRUE;
    case 5: /* any */
        *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
        *preferred = MM_MODEM_MODE_NONE;
        return TRUE;
    default:
        break;
    }

    g_set_error (error,
                 MM_CORE_ERROR,
                 MM_CORE_ERROR_FAILED,
                 "Couldn't parse unexpected OPSYS response: '%s'",
                 response);
    return FALSE;
}
static gboolean
load_current_modes_finish (MMIfaceModem *self,
                           GAsyncResult *res,
                           MMModemMode *allowed,
                           MMModemMode *preferred,
                           GError **error)
{
    const gchar *response;
    const gchar *str;
    gint mododr = -1;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
    if (!response)
        return FALSE;

    str = mm_strip_tag (response, "+MODODR:");
    if (!str) {
        g_set_error (error,
                     MM_CORE_ERROR,
                     MM_CORE_ERROR_FAILED,
                     "Couldn't parse MODODR response: '%s'",
                     response);
        return FALSE;
    }

    mododr = atoi (str);
    switch (mododr) {
    case 1:
        /* UMTS only */
        *allowed = MM_MODEM_MODE_3G;
        *preferred = MM_MODEM_MODE_NONE;
        return TRUE;
    case 2:
        /* UMTS preferred */
        *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
        *preferred = MM_MODEM_MODE_3G;
        return TRUE;
    case 3:
        /* GSM only */
        *allowed = MM_MODEM_MODE_2G;
        *preferred = MM_MODEM_MODE_NONE;
        return TRUE;
    case 4:
        /* GSM preferred */
        *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
        *preferred = MM_MODEM_MODE_2G;
        return TRUE;
    default:
        break;
    }

    g_set_error (error,
                 MM_CORE_ERROR,
                 MM_CORE_ERROR_FAILED,
                 "Couldn't parse unexpected MODODR response: '%s'",
                 response);
    return FALSE;
}
static gboolean
load_access_technologies_finish (MMIfaceModem *self,
                                 GAsyncResult *res,
                                 MMModemAccessTechnology *access_technologies,
                                 guint *mask,
                                 GError **error)
{
    MMModemAccessTechnology act;
    const gchar *p;
    const gchar *response;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
    if (!response)
        return FALSE;

    act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
    p = mm_strip_tag (response, "+WGPRSIND:");
    if (p) {
        switch (*p) {
        case '1':
            /* GPRS only */
            act = MM_MODEM_ACCESS_TECHNOLOGY_GPRS;
            break;
        case '2':
            /* EGPRS/EDGE supported */
            act = MM_MODEM_ACCESS_TECHNOLOGY_EDGE;
            break;
        case '3':
            /* 3G R99 supported */
            act = MM_MODEM_ACCESS_TECHNOLOGY_UMTS;
            break;
        case '4':
            /* HSDPA supported */
            act = MM_MODEM_ACCESS_TECHNOLOGY_HSDPA;
            break;
        case '5':
            /* HSUPA supported */
            act = MM_MODEM_ACCESS_TECHNOLOGY_HSUPA;
            break;
        default:
            break;
        }
    }

    if (act == MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN) {
        g_set_error (error,
                     MM_CORE_ERROR,
                     MM_CORE_ERROR_FAILED,
                     "Couldn't parse access technologies result: '%s'",
                     response);
        return FALSE;
    }

    /* We are reporting ALL 3GPP access technologies here */
    *access_technologies = act;
    *mask = MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK;
    return TRUE;
}
static void
get_3g_band_ready (MMBroadbandModemWavecom *self,
                   GAsyncResult *res,
                   GSimpleAsyncResult *operation_result)
{
    const gchar *response;
    const gchar *p;
    GError *error = NULL;
    GArray *bands_array = NULL;
    guint32 wavecom_band;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
    if (!response) {
        /* Let the error be critical. */
        g_simple_async_result_take_error (operation_result, error);
        g_simple_async_result_complete (operation_result);
        g_object_unref (operation_result);
        return;
    }

    /* Example reply:
     *   AT+WUBS? -->
     *            <-- +WUBS: "3",1
     *            <-- OK
     * The "3" meaning here Band I and II are selected.
     */

    p = mm_strip_tag (response, "+WUBS:");
    if (*p == '"')
        p++;

    wavecom_band = atoi (p);
    if (wavecom_band > 0) {
        guint i;

        for (i = 0; i < G_N_ELEMENTS (bands_3g); i++) {
            if (bands_3g[i].wavecom_band_flag & wavecom_band) {
                if (G_UNLIKELY (!bands_array))
                    bands_array = g_array_new (FALSE, FALSE, sizeof (MMModemBand));
                g_array_append_val (bands_array, bands_3g[i].mm_band);
            }
        }
    }

    if (!bands_array)
        g_simple_async_result_set_error (operation_result,
                                         MM_CORE_ERROR,
                                         MM_CORE_ERROR_FAILED,
                                         "Couldn't parse current bands reply: '%s'",
                                         response);
    else
        g_simple_async_result_set_op_res_gpointer (operation_result,
                                                   bands_array,
                                                   (GDestroyNotify)g_array_unref);

    g_simple_async_result_complete (operation_result);
    g_object_unref (operation_result);
}
static gboolean
reset_finish (MMIfaceModem *self,
              GAsyncResult *res,
              GError **error)
{
    /* Ignore errors */
    mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, NULL);
    return TRUE;
}
static gboolean
modem_power_up_finish (MMIfaceModem *self,
                       GAsyncResult *res,
                       GError **error)
{
    /* By default, errors in the power up command are ignored. */
    mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, NULL);
    return TRUE;
}
static void
supported_ms_classes_query_ready (MMBaseModem *self,
                                  GAsyncResult *res,
                                  GSimpleAsyncResult *simple)
{
    const gchar *response;
    GError *error = NULL;
    MMModemMode mode;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
    if (!response) {
        /* Let the error be critical. */
        g_simple_async_result_take_error (simple, error);
        g_simple_async_result_complete (simple);
        g_object_unref (simple);
        return;
    }

    response = mm_strip_tag (response, "+CGCLASS:");
    mode = MM_MODEM_MODE_NONE;

    if (strstr (response, WAVECOM_MS_CLASS_A_IDSTR)) {
        mm_dbg ("Modem supports Class A mobile station");
        mode |= MM_MODEM_MODE_3G;
    }

    if (strstr (response, WAVECOM_MS_CLASS_B_IDSTR)) {
        mm_dbg ("Modem supports Class B mobile station");
        mode |= (MM_MODEM_MODE_2G | MM_MODEM_MODE_CS);
    }

    if (strstr (response, WAVECOM_MS_CLASS_CG_IDSTR)) {
        mm_dbg ("Modem supports Class CG mobile station");
        mode |= MM_MODEM_MODE_2G;
    }

    if (strstr (response, WAVECOM_MS_CLASS_CC_IDSTR)) {
        mm_dbg ("Modem supports Class CC mobile station");
        mode |= MM_MODEM_MODE_CS;
    }

    /* If none received, error */
    if (mode == MM_MODEM_MODE_NONE)
        g_simple_async_result_set_error (simple,
                                         MM_CORE_ERROR,
                                         MM_CORE_ERROR_FAILED,
                                         "Couldn't get supported mobile station classes: '%s'",
                                         response);
    else
        g_simple_async_result_set_op_res_gpointer (simple,
                                                   GUINT_TO_POINTER (mode),
                                                   NULL);

    g_simple_async_result_complete (simple);
    g_object_unref (simple);
}
static gchar *
modem_time_load_network_time_finish (MMIfaceModemTime *self,
                                     GAsyncResult *res,
                                     GError **error)
{
    const gchar *response;
    gchar *result = NULL;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
    if (response)
        parse_nwltime_reply (response, &result, NULL, error);
    return result;
}
static MMNetworkTimezone *
modem_time_load_network_timezone_finish (MMIfaceModemTime *self,
                                         GAsyncResult *res,
                                         GError **error)
{
    const gchar *response;
    MMNetworkTimezone *tz = NULL;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, NULL);
    if (response)
        parse_nwltime_reply (response, NULL, &tz, error);
    return tz;
}
static void
get_2g_band_ready (MMBroadbandModemWavecom *self,
                   GAsyncResult *res,
                   GSimpleAsyncResult *operation_result)
{
    const gchar *response;
    const gchar *p;
    GError *error = NULL;
    GArray *bands_array = NULL;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
    if (!response) {
        /* Let the error be critical. */
        g_simple_async_result_take_error (operation_result, error);
        g_simple_async_result_complete (operation_result);
        g_object_unref (operation_result);
        return;
    }

    p = mm_strip_tag (response, "+WMBS:");
    if (p) {
        guint i;

        for (i = 0; i < G_N_ELEMENTS (bands_2g); i++) {
            if (bands_2g[i].wavecom_band == *p) {
                guint j;

                if (G_UNLIKELY (!bands_array))
                    bands_array = g_array_new (FALSE, FALSE, sizeof (MMModemBand));

                for (j = 0; j < bands_2g[i].n_mm_bands; j++)
                    g_array_append_val (bands_array, bands_2g[i].mm_bands[j]);
            }
        }
    }

    if (!bands_array)
        g_simple_async_result_set_error (operation_result,
                                         MM_CORE_ERROR,
                                         MM_CORE_ERROR_FAILED,
                                         "Couldn't parse current bands reply: '%s'",
                                         response);
    else
        g_simple_async_result_set_op_res_gpointer (operation_result,
                                                   bands_array,
                                                   (GDestroyNotify)g_array_unref);

    g_simple_async_result_complete (operation_result);
    g_object_unref (operation_result);
}
static void
modem_power_down_ready (MMBaseModem *self,
                       GAsyncResult *res,
                       GSimpleAsyncResult *simple)
{
    /* Ignore errors for now; we're not sure if all Sierra CDMA devices support
     * at!pcstate or 3GPP devices support +CFUN=4.
     */
    mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, NULL);

    g_simple_async_result_set_op_res_gboolean (simple, TRUE);
    g_simple_async_result_complete (simple);
    g_object_unref (simple);
}
static gboolean
load_current_modes_finish (MMIfaceModem *_self,
                           GAsyncResult *res,
                           MMModemMode *allowed,
                           MMModemMode *preferred,
                           GError **error)
{
    MMBroadbandModemMbm *self = MM_BROADBAND_MODEM_MBM (_self);
    const gchar *response;
    guint a;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
    if (!response)
        return FALSE;

    if (mm_get_uint_from_str (mm_strip_tag (response, "+CFUN:"), &a)) {
        /* No settings to set preferred */
        *preferred = MM_MODEM_MODE_NONE;

        switch (a) {
        case MBM_NETWORK_MODE_OFFLINE:
        case MBM_NETWORK_MODE_LOW_POWER:
            /* Do not update internal mbm_mode */
            *allowed = MM_MODEM_MODE_NONE;
            break;
        case MBM_NETWORK_MODE_2G:
            self->priv->mbm_mode = MBM_NETWORK_MODE_2G;
            *allowed = MM_MODEM_MODE_2G;
            break;
        case MBM_NETWORK_MODE_3G:
            self->priv->mbm_mode = MBM_NETWORK_MODE_3G;
            *allowed = MM_MODEM_MODE_3G;
            break;
        default:
            /* Do not update internal mbm_mode */
            *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
            break;
        }

        return TRUE;
    }

    g_set_error (error,
                 MM_CORE_ERROR,
                 MM_CORE_ERROR_FAILED,
                 "Couldn't parse +CFUN response: '%s'",
                 response);
    return FALSE;
}
static void
set_bands_done (MMIfaceModem *self,
                GAsyncResult *res,
                GSimpleAsyncResult *operation_result)
{
    GError *error = NULL;

    if (!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error))
        g_simple_async_result_take_error (operation_result, error);
    else
        g_simple_async_result_set_op_res_gboolean (operation_result, TRUE);

    g_simple_async_result_complete (operation_result);
    g_object_unref (operation_result);
}
static void
wwsm_update_ready (MMBaseModem *self,
                   GAsyncResult *res,
                   SetAllowedModesContext *ctx)
{
    GError *error = NULL;

    mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
    if (error)
        /* Let the error be critical. */
        g_simple_async_result_take_error (ctx->result, error);
    else
        g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);

    set_allowed_modes_context_complete_and_free (ctx);
}
static void
wmbs_set_ready (MMBaseModem *self,
                GAsyncResult *res,
                GSimpleAsyncResult *operation_result)
{
    GError *error = NULL;

    if (!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error))
        /* Let the error be critical */
        g_simple_async_result_take_error (operation_result, error);
    else
        g_simple_async_result_set_op_res_gboolean (operation_result, TRUE);

    g_simple_async_result_complete (operation_result);
    g_object_unref (operation_result);
}
static void
allowed_mode_update_ready (MMBroadbandModemNovatel *self,
                           GAsyncResult *res,
                           GSimpleAsyncResult *operation_result)
{
    GError *error = NULL;

    mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
    if (error)
        /* Let the error be critical. */
        g_simple_async_result_take_error (operation_result, error);
    else
        g_simple_async_result_set_op_res_gboolean (operation_result, TRUE);
    g_simple_async_result_complete (operation_result);
    g_object_unref (operation_result);
}
static gchar *
modem_time_load_network_time_finish (MMIfaceModemTime *self,
                                     GAsyncResult *res,
                                     GError **error)
{
    const gchar *response = NULL;
    char *iso8601 = NULL;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
    if (response) {
        if (strstr (response, "!TIME:"))
            iso8601 = parse_3gpp_time (response, error);
        else
            iso8601 = parse_cdma_time (response, error);
    }
    return iso8601;
}
static void
setup_flow_control_ready (MMBroadbandModemIridium *self,
                          GAsyncResult *res,
                          GSimpleAsyncResult *operation_result)
{
    GError *error = NULL;

    if (!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error))
        /* Let the error be critical. We DO need RTS/CTS in order to have
         * proper modem disabling. */
        g_simple_async_result_take_error (operation_result, error);
    else
        g_simple_async_result_set_op_res_gboolean (operation_result, TRUE);

    g_simple_async_result_complete (operation_result);
    g_object_unref (operation_result);
}