/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * mmcli -- Control modem status & access information from the command line * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Copyright (C) 2011 Aleksander Morgado */ #include #include #define _LIBMM_INSIDE_MMCLI #include #include "mmcli-common.h" /******************************************************************************/ /* Manager */ MMManager * mmcli_get_manager_finish (GAsyncResult *res) { return g_task_propagate_pointer (G_TASK (res), NULL); } static void manager_new_ready (GDBusConnection *connection, GAsyncResult *res, GTask *task) { MMManager *manager; gchar *name_owner; GError *error = NULL; manager = mm_manager_new_finish (res, &error); if (!manager) { g_printerr ("error: couldn't create manager: %s\n", error ? error->message : "unknown error"); exit (EXIT_FAILURE); } name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (manager)); if (!name_owner) { g_printerr ("error: couldn't find the ModemManager process in the bus\n"); exit (EXIT_FAILURE); } g_debug ("ModemManager process found at '%s'", name_owner); g_free (name_owner); g_task_return_pointer (task, manager, g_object_unref); g_object_unref (task); } void mmcli_get_manager (GDBusConnection *connection, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; task = g_task_new (connection, cancellable, callback, user_data); mm_manager_new (connection, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, cancellable, (GAsyncReadyCallback)manager_new_ready, task); } MMManager * mmcli_get_manager_sync (GDBusConnection *connection) { MMManager *manager; gchar *name_owner; GError *error = NULL; manager = mm_manager_new_sync (connection, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, NULL, &error); if (!manager) { g_printerr ("error: couldn't create manager: %s\n", error ? error->message : "unknown error"); exit (EXIT_FAILURE); } name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (manager)); if (!name_owner) { g_printerr ("error: couldn't find the ModemManager process in the bus\n"); exit (EXIT_FAILURE); } g_debug ("ModemManager process found at '%s'", name_owner); g_free (name_owner); return manager; } /******************************************************************************/ /* Modem */ static MMObject * find_modem (MMManager *manager, const gchar *modem_path, const gchar *modem_uid) { GList *modems; GList *l; MMObject *found = NULL; g_assert (modem_path || modem_uid); g_assert (!(modem_path && modem_uid)); modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (manager)); for (l = modems; l; l = g_list_next (l)) { MMObject *obj; MMModem *modem; obj = MM_OBJECT (l->data); modem = MM_MODEM (mm_object_get_modem (obj)); if (modem_path && g_str_equal (mm_object_get_path (obj), modem_path)) { found = g_object_ref (obj); break; } if (modem_uid && g_str_equal (mm_modem_get_device (modem), modem_uid)) { found = g_object_ref (obj); break; } } g_list_free_full (modems, g_object_unref); if (!found) { if (modem_path) g_printerr ("error: couldn't find modem at '%s'\n", modem_path); else if (modem_uid) g_printerr ("error: couldn't find modem identified by uid '%s'\n", modem_uid); exit (EXIT_FAILURE); } g_debug ("Modem found at '%s'\n", modem_path); return found; } typedef struct { gchar *modem_path; gchar *modem_uid; } GetModemContext; typedef struct { MMManager *manager; MMObject *object; } GetModemResults; static void get_modem_results_free (GetModemResults *results) { g_object_unref (results->manager); g_object_unref (results->object); g_free (results); } static void get_modem_context_free (GetModemContext *ctx) { g_free (ctx->modem_path); g_free (ctx->modem_uid); g_free (ctx); } MMObject * mmcli_get_modem_finish (GAsyncResult *res, MMManager **o_manager) { GetModemResults *results; MMObject *obj; results = g_task_propagate_pointer (G_TASK (res), NULL); g_assert (results); if (o_manager) *o_manager = g_object_ref (results->manager); obj = g_object_ref (results->object); get_modem_results_free (results); return obj; } static void get_manager_ready (GDBusConnection *connection, GAsyncResult *res, GTask *task) { GetModemResults *results; GetModemContext *ctx; ctx = g_task_get_task_data (task); results = g_new (GetModemResults, 1); results->manager = mmcli_get_manager_finish (res); results->object = find_modem (results->manager, ctx->modem_path, ctx->modem_uid); g_task_return_pointer (task, results, (GDestroyNotify)get_modem_results_free); g_object_unref (task); } static void get_modem_path_or_uid (const gchar *str, gchar **modem_path, gchar **modem_uid) { gboolean all_numeric; guint i; /* We must have a given modem specified */ if (!str || !str[0]) { g_printerr ("error: no modem was specified\n"); exit (EXIT_FAILURE); } /* Modem path may come in three ways: * a) full DBus path * b) modem index * c) uid */ *modem_path = NULL; *modem_uid = NULL; /* If we have DBus prefix, we have the modem DBus path */ if (g_str_has_prefix (str, MM_DBUS_MODEM_PREFIX)) { g_debug ("Assuming '%s' is the full modem path", str); *modem_path = g_strdup (str); return; } /* If all numeric, we have the modem index */ all_numeric = TRUE; for (i = 0; str[i]; i++) { if (!g_ascii_isdigit (str[i])) { all_numeric = FALSE; break; } } if (all_numeric) { g_debug ("Assuming '%s' is the modem index", str); *modem_path = g_strdup_printf (MM_DBUS_MODEM_PREFIX "/%s", str); return; } /* Otherwise we have the UID */ *modem_uid = g_strdup (str); } void mmcli_get_modem (GDBusConnection *connection, const gchar *modem_str, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; GetModemContext *ctx; task = g_task_new (connection, cancellable, callback, user_data); ctx = g_new0 (GetModemContext, 1); get_modem_path_or_uid (modem_str, &ctx->modem_path, &ctx->modem_uid); g_assert (ctx->modem_path || ctx->modem_uid); g_task_set_task_data (task, ctx, (GDestroyNotify) get_modem_context_free); mmcli_get_manager (connection, cancellable, (GAsyncReadyCallback)get_manager_ready, task); } MMObject * mmcli_get_modem_sync (GDBusConnection *connection, const gchar *modem_str, MMManager **o_manager) { MMManager *manager; MMObject *found; gchar *modem_path = NULL; gchar *modem_uid = NULL; manager = mmcli_get_manager_sync (connection); get_modem_path_or_uid (modem_str, &modem_path, &modem_uid); g_assert (modem_path || modem_uid); found = find_modem (manager, modem_path, modem_uid); if (o_manager) *o_manager = manager; else g_object_unref (manager); g_free (modem_path); g_free (modem_uid); return found; } /******************************************************************************/ /* Bearer */ typedef struct { gchar *bearer_path; MMManager *manager; GList *modems; MMObject *current; } GetBearerContext; typedef struct { MMManager *manager; MMObject *object; MMBearer *bearer; } GetBearerResults; static void get_bearer_results_free (GetBearerResults *results) { g_object_unref (results->manager); g_object_unref (results->object); g_object_unref (results->bearer); g_free (results); } static void get_bearer_context_free (GetBearerContext *ctx) { if (ctx->current) g_object_unref (ctx->current); if (ctx->manager) g_object_unref (ctx->manager); g_list_free_full (ctx->modems, g_object_unref); g_free (ctx->bearer_path); g_free (ctx); } MMBearer * mmcli_get_bearer_finish (GAsyncResult *res, MMManager **o_manager, MMObject **o_object) { GetBearerResults *results; MMBearer *obj; results = g_task_propagate_pointer (G_TASK (res), NULL); g_assert (results); if (o_manager) *o_manager = g_object_ref (results->manager); if (o_object) *o_object = g_object_ref (results->object); obj = g_object_ref (results->bearer); get_bearer_results_free (results); return obj; } static void look_for_bearer_in_modem (GTask *task); static MMBearer * find_bearer_in_list (GList *list, const gchar *bearer_path) { GList *l; for (l = list; l; l = g_list_next (l)) { MMBearer *bearer = MM_BEARER (l->data); if (g_str_equal (mm_bearer_get_path (bearer), bearer_path)) { g_debug ("Bearer found at '%s'\n", bearer_path); return g_object_ref (bearer); } } return NULL; } static void list_bearers_ready (MMModem *modem, GAsyncResult *res, GTask *task) { GetBearerContext *ctx; GetBearerResults *results; MMBearer *found; GList *bearers; GError *error = NULL; ctx = g_task_get_task_data (task); bearers = mm_modem_list_bearers_finish (modem, res, &error); if (error) { g_printerr ("error: couldn't list bearers at '%s': '%s'\n", mm_modem_get_path (modem), error->message); exit (EXIT_FAILURE); } found = find_bearer_in_list (bearers, ctx->bearer_path); g_list_free_full (bearers, g_object_unref); if (!found) { /* Not found, try with next modem */ look_for_bearer_in_modem (task); return; } /* Found! */ results = g_new (GetBearerResults, 1); results->manager = g_object_ref (ctx->manager); results->object = g_object_ref (ctx->current); results->bearer = found; g_task_return_pointer (task, results, (GDestroyNotify) get_bearer_results_free); g_object_unref (task); } static void look_for_bearer_in_modem_bearer_list (GTask *task) { GetBearerContext *ctx; MMModem *modem; ctx = g_task_get_task_data (task); g_assert (ctx->current); modem = mm_object_get_modem (ctx->current); mm_modem_list_bearers (modem, g_task_get_cancellable (task), (GAsyncReadyCallback)list_bearers_ready, task); g_object_unref (modem); } static void get_initial_eps_bearer_ready (MMModem3gpp *modem3gpp, GAsyncResult *res, GTask *task) { GetBearerContext *ctx; MMBearer *bearer; GetBearerResults *results; ctx = g_task_get_task_data (task); bearer = mm_modem_3gpp_get_initial_eps_bearer_finish (modem3gpp, res, NULL); if (!bearer) { look_for_bearer_in_modem_bearer_list (task); return; } /* Found! */ results = g_new (GetBearerResults, 1); results->manager = g_object_ref (ctx->manager); results->object = g_object_ref (ctx->current); results->bearer = bearer; g_task_return_pointer (task, results, (GDestroyNotify) get_bearer_results_free); g_object_unref (task); } static void look_for_bearer_in_modem_3gpp_eps_initial_bearer (GTask *task) { GetBearerContext *ctx; MMModem3gpp *modem3gpp; ctx = g_task_get_task_data (task); g_assert (ctx->current); modem3gpp = mm_object_get_modem_3gpp (ctx->current); if (!modem3gpp) { look_for_bearer_in_modem_bearer_list (task); return; } if (!g_strcmp0 (mm_modem_3gpp_get_initial_eps_bearer_path (modem3gpp), ctx->bearer_path)) mm_modem_3gpp_get_initial_eps_bearer (modem3gpp, g_task_get_cancellable (task), (GAsyncReadyCallback)get_initial_eps_bearer_ready, task); else look_for_bearer_in_modem_bearer_list (task); g_object_unref (modem3gpp); } static void look_for_bearer_in_modem (GTask *task) { GetBearerContext *ctx; MMModem *modem; ctx = g_task_get_task_data (task); if (!ctx->modems) { g_printerr ("error: couldn't find bearer at '%s': 'not found in any modem'\n", ctx->bearer_path); exit (EXIT_FAILURE); } /* Loop looking for the bearer in each modem found */ ctx->current = MM_OBJECT (ctx->modems->data); ctx->modems = g_list_delete_link (ctx->modems, ctx->modems); modem = mm_object_get_modem (ctx->current); /* Don't look for bearers in modems which are not fully initialized */ if (mm_modem_get_state (modem) < MM_MODEM_STATE_DISABLED) { g_debug ("Skipping modem '%s' when looking for bearers " "(not fully initialized)", mm_object_get_path (ctx->current)); look_for_bearer_in_modem (task); } else { g_debug ("Looking for bearer '%s' in modem '%s'...", ctx->bearer_path, mm_object_get_path (ctx->current)); look_for_bearer_in_modem_3gpp_eps_initial_bearer (task); } g_object_unref (modem); } static void get_bearer_manager_ready (GDBusConnection *connection, GAsyncResult *res, GTask *task) { GetBearerContext *ctx; ctx = g_task_get_task_data (task); ctx->manager = mmcli_get_manager_finish (res); ctx->modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (ctx->manager)); if (!ctx->modems) { g_printerr ("error: couldn't find bearer at '%s': 'no modems found'\n", ctx->bearer_path); exit (EXIT_FAILURE); } look_for_bearer_in_modem (task); } static gchar * get_bearer_path (const gchar *path_or_index) { gchar *bearer_path; /* We must have a given bearer specified */ if (!path_or_index) { g_printerr ("error: no bearer was specified\n"); exit (EXIT_FAILURE); } /* Bearer path may come in two ways: full DBus path or just bearer index. * If it is a bearer index, we'll need to generate the DBus path ourselves */ if (g_str_has_prefix (path_or_index, MM_DBUS_BEARER_PREFIX)) { g_debug ("Assuming '%s' is the full bearer path", path_or_index); bearer_path = g_strdup (path_or_index); } else if (g_ascii_isdigit (path_or_index[0])) { g_debug ("Assuming '%s' is the bearer index", path_or_index); bearer_path = g_strdup_printf (MM_DBUS_BEARER_PREFIX "/%s", path_or_index); } else { g_printerr ("error: invalid path or index string specified: '%s'\n", path_or_index); exit (EXIT_FAILURE); } return bearer_path; } void mmcli_get_bearer (GDBusConnection *connection, const gchar *path_or_index, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; GetBearerContext *ctx; task = g_task_new (connection, cancellable, callback, user_data); ctx = g_new0 (GetBearerContext, 1); ctx->bearer_path = get_bearer_path (path_or_index); g_task_set_task_data (task, ctx, (GDestroyNotify) get_bearer_context_free); mmcli_get_manager (connection, cancellable, (GAsyncReadyCallback)get_bearer_manager_ready, task); } MMBearer * mmcli_get_bearer_sync (GDBusConnection *connection, const gchar *path_or_index, MMManager **o_manager, MMObject **o_object) { MMManager *manager; GList *modems; GList *l; MMBearer *found = NULL; gchar *bearer_path; bearer_path = get_bearer_path (path_or_index); manager = mmcli_get_manager_sync (connection); modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (manager)); if (!modems) { g_printerr ("error: couldn't find bearer at '%s': 'no modems found'\n", bearer_path); exit (EXIT_FAILURE); } for (l = modems; !found && l; l = g_list_next (l)) { GError *error = NULL; MMObject *object; MMModem *modem; MMModem3gpp *modem3gpp; object = MM_OBJECT (l->data); modem = mm_object_get_modem (object); modem3gpp = mm_object_get_modem_3gpp (object); /* Don't look for bearers in modems which are not fully initialized */ if (mm_modem_get_state (modem) < MM_MODEM_STATE_DISABLED) { g_debug ("Skipping modem '%s' when looking for bearers " "(not fully initialized)", mm_object_get_path (object)); goto next; } if (modem3gpp && !g_strcmp0 (mm_modem_3gpp_get_initial_eps_bearer_path (modem3gpp), bearer_path)) { found = mm_modem_3gpp_get_initial_eps_bearer_sync (modem3gpp, NULL, &error); if (!found) { g_printerr ("error: couldn't get initial EPS bearer object at '%s': '%s'\n", mm_modem_get_path (modem), error->message); exit (EXIT_FAILURE); } } else { GList *bearers; bearers = mm_modem_list_bearers_sync (modem, NULL, &error); if (error) { g_printerr ("error: couldn't list bearers at '%s': '%s'\n", mm_modem_get_path (modem), error->message); exit (EXIT_FAILURE); } found = find_bearer_in_list (bearers, bearer_path); g_list_free_full (bearers, g_object_unref); } if (found && o_object) *o_object = g_object_ref (object); next: g_clear_object (&modem); g_clear_object (&modem3gpp); } if (!found) { g_printerr ("error: couldn't find bearer at '%s': 'not found in any modem'\n", bearer_path); exit (EXIT_FAILURE); } g_list_free_full (modems, g_object_unref); g_free (bearer_path); if (o_manager) *o_manager = manager; else g_object_unref (manager); return found; } /******************************************************************************/ /* SIM */ typedef struct { gchar *sim_path; MMManager *manager; MMObject *current; } GetSimContext; typedef struct { MMManager *manager; MMObject *object; MMSim *sim; } GetSimResults; static void get_sim_results_free (GetSimResults *results) { g_object_unref (results->manager); g_object_unref (results->object); g_object_unref (results->sim); g_free (results); } static void get_sim_context_free (GetSimContext *ctx) { if (ctx->current) g_object_unref (ctx->current); if (ctx->manager) g_object_unref (ctx->manager); g_free (ctx->sim_path); g_free (ctx); } MMSim * mmcli_get_sim_finish (GAsyncResult *res, MMManager **o_manager, MMObject **o_object) { GetSimResults *results; MMSim *obj; results = g_task_propagate_pointer (G_TASK (res), NULL); g_assert (results); if (o_manager) *o_manager = g_object_ref (results->manager); if (o_object) *o_object = g_object_ref (results->object); obj = g_object_ref (results->sim); get_sim_results_free (results); return obj; } static void get_sim_ready (MMModem *modem, GAsyncResult *res, GTask *task) { GetSimContext *ctx; GetSimResults *results; MMSim *sim; GError *error = NULL; ctx = g_task_get_task_data (task); sim = mm_modem_get_sim_finish (modem, res, &error); if (error) { g_printerr ("error: couldn't get sim '%s' at '%s': '%s'\n", ctx->sim_path, mm_modem_get_path (modem), error->message); exit (EXIT_FAILURE); } /* Found! */ results = g_new (GetSimResults, 1); results->manager = g_object_ref (ctx->manager); results->object = g_object_ref (ctx->current); results->sim = sim; g_task_return_pointer (task, results, (GDestroyNotify) get_sim_results_free); g_object_unref (task); } static void get_sim_manager_ready (GDBusConnection *connection, GAsyncResult *res, GTask *task) { GetSimContext *ctx; GList *l; GList *modems; ctx = g_task_get_task_data (task); ctx->manager = mmcli_get_manager_finish (res); modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (ctx->manager)); if (!modems) { g_printerr ("error: couldn't find sim at '%s': 'no modems found'\n", ctx->sim_path); exit (EXIT_FAILURE); } for (l = modems; l && !ctx->current; l = g_list_next (l)) { MMObject *object; MMModem *modem; object = MM_OBJECT (l->data); modem = mm_object_get_modem (object); if (g_str_equal (ctx->sim_path, mm_modem_get_sim_path (modem))) { ctx->current = g_object_ref (object); mm_modem_get_sim (modem, g_task_get_cancellable (task), (GAsyncReadyCallback)get_sim_ready, task); } g_object_unref (modem); } g_list_free_full (modems, g_object_unref); if (!ctx->current) { g_printerr ("error: couldn't find sim at '%s'\n", ctx->sim_path); exit (EXIT_FAILURE); } } static gchar * get_sim_path (const gchar *path_or_index) { gchar *sim_path; /* We must have a given sim specified */ if (!path_or_index) { g_printerr ("error: no sim was specified\n"); exit (EXIT_FAILURE); } /* Sim path may come in two ways: full DBus path or just sim index. * If it is a sim index, we'll need to generate the DBus path ourselves */ if (g_str_has_prefix (path_or_index, MM_DBUS_SIM_PREFIX)) { g_debug ("Assuming '%s' is the full SIM path", path_or_index); sim_path = g_strdup (path_or_index); } else if (g_ascii_isdigit (path_or_index[0])) { g_debug ("Assuming '%s' is the SIM index", path_or_index); sim_path = g_strdup_printf (MM_DBUS_SIM_PREFIX "/%s", path_or_index); } else { g_printerr ("error: invalid index string specified: '%s'\n", path_or_index); exit (EXIT_FAILURE); } return sim_path; } void mmcli_get_sim (GDBusConnection *connection, const gchar *path_or_index, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; GetSimContext *ctx; task = g_task_new (connection, cancellable, callback, user_data); ctx = g_new0 (GetSimContext, 1); ctx->sim_path = get_sim_path (path_or_index); g_task_set_task_data (task, ctx, (GDestroyNotify) get_sim_context_free); mmcli_get_manager (connection, cancellable, (GAsyncReadyCallback)get_sim_manager_ready, task); } MMSim * mmcli_get_sim_sync (GDBusConnection *connection, const gchar *path_or_index, MMManager **o_manager, MMObject **o_object) { MMManager *manager; GList *modems; GList *l; MMSim *found = NULL; gchar *sim_path; sim_path = get_sim_path (path_or_index); manager = mmcli_get_manager_sync (connection); modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (manager)); if (!modems) { g_printerr ("error: couldn't find sim at '%s': 'no modems found'\n", sim_path); exit (EXIT_FAILURE); } for (l = modems; !found && l; l = g_list_next (l)) { GError *error = NULL; MMObject *object; MMModem *modem; object = MM_OBJECT (l->data); modem = mm_object_get_modem (object); if (g_str_equal (sim_path, mm_modem_get_sim_path (modem))) { found = mm_modem_get_sim_sync (modem, NULL, &error); if (error) { g_printerr ("error: couldn't get sim '%s' in modem '%s': '%s'\n", sim_path, mm_modem_get_path (modem), error->message); exit (EXIT_FAILURE); } if (found && o_object) *o_object = g_object_ref (object); } g_object_unref (modem); } if (!found) { g_printerr ("error: couldn't find sim at '%s'\n", sim_path); exit (EXIT_FAILURE); } g_list_free_full (modems, g_object_unref); g_free (sim_path); if (o_manager) *o_manager = manager; else g_object_unref (manager); return found; } /******************************************************************************/ /* SMS */ typedef struct { gchar *sms_path; MMManager *manager; GList *modems; MMObject *current; } GetSmsContext; typedef struct { MMManager *manager; MMObject *object; MMSms *sms; } GetSmsResults; static void get_sms_results_free (GetSmsResults *results) { g_object_unref (results->manager); g_object_unref (results->object); g_object_unref (results->sms); g_free (results); } static void get_sms_context_free (GetSmsContext *ctx) { if (ctx->current) g_object_unref (ctx->current); if (ctx->manager) g_object_unref (ctx->manager); g_list_free_full (ctx->modems, g_object_unref); g_free (ctx->sms_path); g_free (ctx); } MMSms * mmcli_get_sms_finish (GAsyncResult *res, MMManager **o_manager, MMObject **o_object) { GetSmsResults *results; MMSms *obj; results = g_task_propagate_pointer (G_TASK (res), NULL); g_assert (results); if (o_manager) *o_manager = g_object_ref (results->manager); if (o_object) *o_object = g_object_ref (results->object); obj = g_object_ref (results->sms); get_sms_results_free (results); return obj; } static void look_for_sms_in_modem (GTask *task); static MMSms * find_sms_in_list (GList *list, const gchar *sms_path) { GList *l; for (l = list; l; l = g_list_next (l)) { MMSms *sms = MM_SMS (l->data); if (g_str_equal (mm_sms_get_path (sms), sms_path)) { g_debug ("Sms found at '%s'\n", sms_path); return g_object_ref (sms); } } return NULL; } static void list_sms_ready (MMModemMessaging *modem, GAsyncResult *res, GTask *task) { GetSmsContext *ctx; GetSmsResults *results; MMSms *found; GList *sms_list; GError *error = NULL; ctx = g_task_get_task_data (task); sms_list = mm_modem_messaging_list_finish (modem, res, &error); if (error) { g_printerr ("error: couldn't list SMS at '%s': '%s'\n", mm_modem_messaging_get_path (modem), error->message); exit (EXIT_FAILURE); } found = find_sms_in_list (sms_list, ctx->sms_path); g_list_free_full (sms_list, g_object_unref); if (!found) { /* Not found, try with next modem */ look_for_sms_in_modem (task); return; } /* Found! */ results = g_new (GetSmsResults, 1); results->manager = g_object_ref (ctx->manager); results->object = g_object_ref (ctx->current); results->sms = found; g_task_return_pointer (task, results, (GDestroyNotify) get_sms_results_free); g_object_unref (task); } static void look_for_sms_in_modem (GTask *task) { GetSmsContext *ctx; MMModemMessaging *modem; ctx = g_task_get_task_data (task); if (!ctx->modems) { g_printerr ("error: couldn't find SMS at '%s': 'not found in any modem'\n", ctx->sms_path); exit (EXIT_FAILURE); } /* Loop looking for the sms in each modem found */ ctx->current = MM_OBJECT (ctx->modems->data); ctx->modems = g_list_delete_link (ctx->modems, ctx->modems); modem = mm_object_get_modem_messaging (ctx->current); if (!modem) { /* Current modem has no messaging capabilities, try with next modem */ look_for_sms_in_modem (task); return; } g_debug ("Looking for sms '%s' in modem '%s'...", ctx->sms_path, mm_object_get_path (ctx->current)); mm_modem_messaging_list (modem, g_task_get_cancellable (task), (GAsyncReadyCallback)list_sms_ready, task); g_object_unref (modem); } static void get_sms_manager_ready (GDBusConnection *connection, GAsyncResult *res, GTask *task) { GetSmsContext *ctx; ctx = g_task_get_task_data (task); ctx->manager = mmcli_get_manager_finish (res); ctx->modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (ctx->manager)); if (!ctx->modems) { g_printerr ("error: couldn't find SMS at '%s': 'no modems found'\n", ctx->sms_path); exit (EXIT_FAILURE); } look_for_sms_in_modem (task); } static gchar * get_sms_path (const gchar *path_or_index) { gchar *sms_path; /* We must have a given sms specified */ if (!path_or_index) { g_printerr ("error: no SMS was specified\n"); exit (EXIT_FAILURE); } /* Sms path may come in two ways: full DBus path or just sms index. * If it is a sms index, we'll need to generate the DBus path ourselves */ if (g_str_has_prefix (path_or_index, MM_DBUS_SMS_PREFIX)) { g_debug ("Assuming '%s' is the full SMS path", path_or_index); sms_path = g_strdup (path_or_index); } else if (g_ascii_isdigit (path_or_index[0])) { g_debug ("Assuming '%s' is the SMS index", path_or_index); sms_path = g_strdup_printf (MM_DBUS_SMS_PREFIX "/%s", path_or_index); } else { g_printerr ("error: invalid path or index string specified: '%s'\n", path_or_index); exit (EXIT_FAILURE); } return sms_path; } void mmcli_get_sms (GDBusConnection *connection, const gchar *path_or_index, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; GetSmsContext *ctx; task = g_task_new (connection, cancellable, callback, user_data); ctx = g_new0 (GetSmsContext, 1); ctx->sms_path = get_sms_path (path_or_index); g_task_set_task_data (task, ctx, (GDestroyNotify) get_sms_context_free); mmcli_get_manager (connection, cancellable, (GAsyncReadyCallback)get_sms_manager_ready, task); } MMSms * mmcli_get_sms_sync (GDBusConnection *connection, const gchar *path_or_index, MMManager **o_manager, MMObject **o_object) { MMManager *manager; GList *modems; GList *l; MMSms *found = NULL; gchar *sms_path; sms_path = get_sms_path (path_or_index); manager = mmcli_get_manager_sync (connection); modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (manager)); if (!modems) { g_printerr ("error: couldn't find sms at '%s': 'no modems found'\n", sms_path); exit (EXIT_FAILURE); } for (l = modems; !found && l; l = g_list_next (l)) { GError *error = NULL; MMObject *object; MMModemMessaging *modem; GList *sms_list; object = MM_OBJECT (l->data); modem = mm_object_get_modem_messaging (object); /* If this modem doesn't implement messaging, continue to next one */ if (!modem) continue; sms_list = mm_modem_messaging_list_sync (modem, NULL, &error); if (error) { g_printerr ("error: couldn't list SMS at '%s': '%s'\n", mm_modem_messaging_get_path (modem), error->message); exit (EXIT_FAILURE); } found = find_sms_in_list (sms_list, sms_path); g_list_free_full (sms_list, g_object_unref); if (found && o_object) *o_object = g_object_ref (object); g_object_unref (modem); } if (!found) { g_printerr ("error: couldn't find SMS at '%s': 'not found in any modem'\n", sms_path); exit (EXIT_FAILURE); } g_list_free_full (modems, g_object_unref); g_free (sms_path); if (o_manager) *o_manager = manager; else g_object_unref (manager); return found; } /******************************************************************************/ /* Call */ typedef struct { gchar *call_path; MMManager *manager; GList *modems; MMObject *current; } GetCallContext; typedef struct { MMManager *manager; MMObject *object; MMCall *call; } GetCallResults; static void get_call_results_free (GetCallResults *results) { g_object_unref (results->manager); g_object_unref (results->object); g_object_unref (results->call); g_free (results); } static void get_call_context_free (GetCallContext *ctx) { if (ctx->current) g_object_unref (ctx->current); if (ctx->manager) g_object_unref (ctx->manager); g_list_free_full (ctx->modems, g_object_unref); g_free (ctx->call_path); g_free (ctx); } MMCall * mmcli_get_call_finish (GAsyncResult *res, MMManager **o_manager, MMObject **o_object) { GetCallResults *results; MMCall *obj; results = g_task_propagate_pointer (G_TASK (res), NULL); g_assert (results); if (o_manager) *o_manager = g_object_ref (results->manager); if (o_object) *o_object = g_object_ref (results->object); obj = g_object_ref (results->call); get_call_results_free (results); return obj; } static void look_for_call_in_modem (GTask *task); static MMCall * find_call_in_list (GList *list, const gchar *call_path) { GList *l; for (l = list; l; l = g_list_next (l)) { MMCall *call = MM_CALL (l->data); if (g_str_equal (mm_call_get_path (call), call_path)) { g_debug ("Call found at '%s'\n", call_path); return g_object_ref (call); } } return NULL; } static void list_calls_ready (MMModemVoice *modem, GAsyncResult *res, GTask *task) { GetCallContext *ctx; GetCallResults *results; MMCall *found; GList *call_list; GError *error = NULL; ctx = g_task_get_task_data (task); call_list = mm_modem_voice_list_calls_finish (modem, res, &error); if (error) { g_printerr ("error: couldn't list call at '%s': '%s'\n", mm_modem_voice_get_path (modem), error->message); exit (EXIT_FAILURE); } found = find_call_in_list (call_list, ctx->call_path); g_list_free_full (call_list, g_object_unref); if (!found) { /* Not found, try with next modem */ look_for_call_in_modem (task); return; } /* Found! */ results = g_new (GetCallResults, 1); results->manager = g_object_ref (ctx->manager); results->object = g_object_ref (ctx->current); results->call = found; g_task_return_pointer (task, results, (GDestroyNotify) get_call_results_free); g_object_unref (task); } static void look_for_call_in_modem (GTask *task) { GetCallContext *ctx; MMModemVoice *modem; ctx = g_task_get_task_data (task); if (!ctx->modems) { g_printerr ("error: couldn't find call at '%s': 'not found in any modem'\n", ctx->call_path); exit (EXIT_FAILURE); } /* Loop looking for the call in each modem found */ ctx->current = MM_OBJECT (ctx->modems->data); ctx->modems = g_list_delete_link (ctx->modems, ctx->modems); modem = mm_object_get_modem_voice (ctx->current); if (!modem) { /* Current modem has no messaging capabilities, try with next modem */ look_for_call_in_modem (task); return; } g_debug ("Looking for call '%s' in modem '%s'...", ctx->call_path, mm_object_get_path (ctx->current)); mm_modem_voice_list_calls (modem, g_task_get_cancellable (task), (GAsyncReadyCallback)list_calls_ready, task); g_object_unref (modem); } static void get_call_manager_ready (GDBusConnection *connection, GAsyncResult *res, GTask *task) { GetCallContext *ctx; ctx = g_task_get_task_data (task); ctx->manager = mmcli_get_manager_finish (res); ctx->modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (ctx->manager)); if (!ctx->modems) { g_printerr ("error: couldn't find call at '%s': 'no modems found'\n", ctx->call_path); exit (EXIT_FAILURE); } look_for_call_in_modem (task); } static gchar * get_call_path (const gchar *path_or_index) { gchar *call_path; /* We must have a given call specified */ if (!path_or_index) { g_printerr ("error: no call was specified\n"); exit (EXIT_FAILURE); } /* Call path may come in two ways: full DBus path or just call index. * If it is a call index, we'll need to generate the DBus path ourselves */ if (g_str_has_prefix (path_or_index, MM_DBUS_CALL_PREFIX)) { g_debug ("Assuming '%s' is the full call path", path_or_index); call_path = g_strdup (path_or_index); } else if (g_ascii_isdigit (path_or_index[0])) { g_debug ("Assuming '%s' is the call index", path_or_index); call_path = g_strdup_printf (MM_DBUS_CALL_PREFIX "/%s", path_or_index); } else { g_printerr ("error: invalid path or index string specified: '%s'\n", path_or_index); exit (EXIT_FAILURE); } return call_path; } void mmcli_get_call (GDBusConnection *connection, const gchar *path_or_index, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; GetCallContext *ctx; task = g_task_new (connection, cancellable, callback, user_data); ctx = g_new0 (GetCallContext, 1); ctx->call_path = get_call_path (path_or_index); g_task_set_task_data (task, ctx, (GDestroyNotify) get_call_context_free); mmcli_get_manager (connection, cancellable, (GAsyncReadyCallback)get_call_manager_ready, task); } MMCall * mmcli_get_call_sync (GDBusConnection *connection, const gchar *path_or_index, MMManager **o_manager, MMObject **o_object) { MMManager *manager; GList *modems; GList *l; MMCall *found = NULL; gchar *call_path; call_path = get_call_path (path_or_index); manager = mmcli_get_manager_sync (connection); modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (manager)); if (!modems) { g_printerr ("error: couldn't find sms at '%s': 'no modems found'\n", call_path); exit (EXIT_FAILURE); } for (l = modems; !found && l; l = g_list_next (l)) { GError *error = NULL; MMObject *object; MMModemVoice *voice; GList *call_list; object = MM_OBJECT (l->data); voice = mm_object_get_modem_voice (object); /* If doesn't implement voice, continue to next one */ if (!voice) continue; call_list = mm_modem_voice_list_calls_sync (voice, NULL, &error); if (error) { g_printerr ("error: couldn't list call at '%s': '%s'\n", mm_modem_voice_get_path (voice), error->message); exit (EXIT_FAILURE); } found = find_call_in_list (call_list, call_path); g_list_free_full (call_list, g_object_unref); if (found && o_object) *o_object = g_object_ref (object); g_object_unref (voice); } if (!found) { g_printerr ("error: couldn't find call at '%s': 'not found in any modem'\n", call_path); exit (EXIT_FAILURE); } g_list_free_full (modems, g_object_unref); g_free (call_path); if (o_manager) *o_manager = manager; else g_object_unref (manager); return found; } /******************************************************************************/ const gchar * mmcli_get_state_reason_string (MMModemStateChangeReason reason) { switch (reason) { case MM_MODEM_STATE_CHANGE_REASON_UNKNOWN: return "None or unknown"; case MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED: return "User request"; case MM_MODEM_STATE_CHANGE_REASON_SUSPEND: return "Suspend"; case MM_MODEM_STATE_CHANGE_REASON_FAILURE: return "Failure"; } g_warn_if_reached (); return NULL; } /* Common options */ static gchar *modem_str; static gchar *bearer_str; static gchar *sim_str; static gchar *sms_str; static gchar *call_str; static GOptionEntry entries[] = { { "modem", 'm', 0, G_OPTION_ARG_STRING, &modem_str, "Specify modem by path or index. Shows modem information if no action specified.", "[PATH|INDEX]" }, { "bearer", 'b', 0, G_OPTION_ARG_STRING, &bearer_str, "Specify bearer by path or index. Shows bearer information if no action specified.", "[PATH|INDEX]" }, { "sim", 'i', 0, G_OPTION_ARG_STRING, &sim_str, "Specify SIM card by path or index. Shows SIM card information if no action specified.", "[PATH|INDEX]" }, { "sms", 's', 0, G_OPTION_ARG_STRING, &sms_str, "Specify SMS by path or index. Shows SMS information if no action specified.", "[PATH|INDEX]" }, { "call", 'o', 0, G_OPTION_ARG_STRING, &call_str, "Specify Call by path or index. Shows Call information if no action specified.", "[PATH|INDEX]" }, { NULL } }; GOptionGroup * mmcli_get_common_option_group (void) { GOptionGroup *group; /* Status options */ group = g_option_group_new ("common", "Common options", "Show common options", NULL, NULL); g_option_group_add_entries (group, entries); return group; } const gchar * mmcli_get_common_modem_string (void) { return modem_str; } const gchar * mmcli_get_common_bearer_string (void) { return bearer_str; } const gchar * mmcli_get_common_sim_string (void) { return sim_str; } const gchar * mmcli_get_common_sms_string (void) { return sms_str; } const gchar * mmcli_get_common_call_string (void) { return call_str; } gchar * mmcli_prefix_newlines (const gchar *prefix, const gchar *str) { GString *prefixed_string = NULL; const gchar *line_start = str; const gchar *line_end; do { gssize line_length; line_end = strchr (line_start, '\n'); if (line_end) line_length = line_end - line_start; else line_length = strlen (line_start); if (line_start[line_length - 1] == '\r') line_length--; if (line_length > 0) { if (prefixed_string) { /* If not the first line, add the prefix */ g_string_append_printf (prefixed_string, "\n%s", prefix); } else { prefixed_string = g_string_new (""); } g_string_append_len (prefixed_string, line_start, line_length); } line_start = (line_end ? line_end + 1 : NULL); } while (line_start != NULL); return (prefixed_string ? g_string_free (prefixed_string, FALSE) : g_strdup (str)); }