Files
ModemManager/cli/mmcli-common.c
Aleksander Morgado cc99ab562b cli: consolidate logic to process user provided object lookup info
The user may specify DBus objects in several ways, e.g. with full
object paths, just with the object numeric ids, or in some other cases
with the full device UID.

Setup one single method to process this info for all object types, so
that it's also easier to add new lookup methods for all at the same
time.
2020-04-09 05:38:07 +00:00

1587 lines
44 KiB
C

/* -*- 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 <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2011 Aleksander Morgado <aleksander@gnu.org>
*/
#include <stdlib.h>
#include <string.h>
#define _LIBMM_INSIDE_MMCLI
#include <libmm-glib.h>
#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;
}
/******************************************************************************/
/* Common to all objects */
static void
get_object_lookup_info (const gchar *str,
const gchar *object_type,
const gchar *object_prefix,
gchar **object_path,
gchar **modem_uid)
{
gboolean all_numeric;
guint i;
/* Empty string not allowed */
if (!str || !str[0]) {
g_printerr ("error: no %s was specified\n", object_type);
exit (EXIT_FAILURE);
}
/* User string may come in three ways:
* a) full DBus path
* b) object index
* c) modem UID (for modem or SIM lookup only)
*/
*object_path = NULL;
if (modem_uid)
*modem_uid = NULL;
/* If match the DBus prefix, we have a DBus object path */
if (g_str_has_prefix (str, object_prefix)) {
g_debug ("Assuming '%s' is the full %s path", str, object_type);
*object_path = g_strdup (str);
return;
}
/* If all numeric, we have the object 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 %s index", str, object_type);
*object_path = g_strdup_printf ("%s/%s", object_prefix, str);
return;
}
/* Otherwise we have the UID */
if (modem_uid) {
g_debug ("Assuming '%s' is the modem UID", str);
*modem_uid = g_strdup (str);
return;
}
/* If UID is not a valid input for the object type, error out */
g_printerr ("error: invalid %s string specified: '%s'\n", object_type, str);
exit (EXIT_FAILURE);
}
/******************************************************************************/
/* 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) {
g_printerr ("error: couldn't find modem\n");
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);
}
void
mmcli_get_modem (GDBusConnection *connection,
const gchar *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_object_lookup_info (str, "modem", MM_DBUS_MODEM_PREFIX,
&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 *str,
MMManager **o_manager)
{
MMManager *manager;
MMObject *found;
gchar *modem_path = NULL;
gchar *modem_uid = NULL;
manager = mmcli_get_manager_sync (connection);
get_object_lookup_info (str, "modem", MM_DBUS_MODEM_PREFIX,
&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);
}
void
mmcli_get_bearer (GDBusConnection *connection,
const gchar *str,
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);
get_object_lookup_info (str, "bearer", MM_DBUS_BEARER_PREFIX,
&ctx->bearer_path, NULL);
g_assert (ctx->bearer_path);
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 *str,
MMManager **o_manager,
MMObject **o_object)
{
MMManager *manager;
GList *modems;
GList *l;
MMBearer *found = NULL;
gchar *bearer_path = NULL;
get_object_lookup_info (str, "bearer", MM_DBUS_BEARER_PREFIX,
&bearer_path, NULL);
g_assert (bearer_path);
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;
gchar *modem_uid;
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->modem_uid);
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);
/* check if modem UID matches */
if (ctx->modem_uid) {
if (g_str_equal (ctx->modem_uid, mm_modem_get_device (modem))) {
g_assert (!ctx->sim_path);
ctx->sim_path = g_strdup (mm_modem_get_sim_path (modem));
} else {
g_object_unref (modem);
continue;
}
}
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\n");
exit (EXIT_FAILURE);
}
}
void
mmcli_get_sim (GDBusConnection *connection,
const gchar *str,
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);
get_object_lookup_info (str, "SIM", MM_DBUS_SIM_PREFIX,
&ctx->sim_path, &ctx->modem_uid);
g_assert (ctx->sim_path || ctx->modem_uid);
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 *str,
MMManager **o_manager,
MMObject **o_object)
{
MMManager *manager;
GList *modems;
GList *l;
MMSim *found = NULL;
gchar *sim_path = NULL;
gchar *modem_uid = NULL;
get_object_lookup_info (str, "SIM", MM_DBUS_SIM_PREFIX,
&sim_path, &modem_uid);
g_assert (sim_path || modem_uid);
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);
/* check if modem UID matches */
if (modem_uid) {
if (g_str_equal (modem_uid, mm_modem_get_device (modem))) {
g_assert (!sim_path);
sim_path = g_strdup (mm_modem_get_sim_path (modem));
} else {
g_object_unref (modem);
continue;
}
}
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\n");
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);
}
void
mmcli_get_sms (GDBusConnection *connection,
const gchar *str,
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);
get_object_lookup_info (str, "SMS", MM_DBUS_SMS_PREFIX,
&ctx->sms_path, NULL);
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 *str,
MMManager **o_manager,
MMObject **o_object)
{
MMManager *manager;
GList *modems;
GList *l;
MMSms *found = NULL;
gchar *sms_path = NULL;
get_object_lookup_info (str, "SMS", MM_DBUS_SMS_PREFIX,
&sms_path, NULL);
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);
}
void
mmcli_get_call (GDBusConnection *connection,
const gchar *str,
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);
get_object_lookup_info (str, "call", MM_DBUS_CALL_PREFIX,
&ctx->call_path, NULL);
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 *str,
MMManager **o_manager,
MMObject **o_object)
{
MMManager *manager;
GList *modems;
GList *l;
MMCall *found = NULL;
gchar *call_path = NULL;
get_object_lookup_info (str, "call", MM_DBUS_CALL_PREFIX,
&call_path, NULL);
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 call 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";
default:
g_assert_not_reached ();
}
}
/* 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));
}