/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * 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: * * Copyright (C) 2021 Aleksander Morgado * Copyright (C) 2021 Google, Inc. */ #include #include #include #define _LIBMM_INSIDE_MM #include #include "mm-iface-modem.h" #include "mm-iface-modem-3gpp.h" #include "mm-iface-modem-3gpp-profile-manager.h" #include "mm-base-modem.h" #include "mm-log-object.h" #define SUPPORT_CHECKED_TAG "3gpp-ussd-support-checked-tag" #define SUPPORTED_TAG "3gpp-ussd-supported-tag" static GQuark support_checked_quark; static GQuark supported_quark; /*****************************************************************************/ void mm_iface_modem_3gpp_profile_manager_bind_simple_status (MMIfaceModem3gppProfileManager *self, MMSimpleStatus *status) { /* Nothing shown in simple status */ } /*****************************************************************************/ void mm_iface_modem_3gpp_profile_manager_updated (MMIfaceModem3gppProfileManager *self) { g_autoptr(MmGdbusModem3gppProfileManagerSkeleton) skeleton = NULL; g_object_get (self, MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_DBUS_SKELETON, &skeleton, NULL); if (skeleton) mm_gdbus_modem3gpp_profile_manager_emit_updated (MM_GDBUS_MODEM3GPP_PROFILE_MANAGER (skeleton)); } static gboolean profile_manager_fail_if_connected_bearer (MMIfaceModem3gppProfileManager *self, gint profile_id, GError **error) { g_autoptr(MMBearerList) bearer_list = NULL; g_autoptr(MMBaseBearer) bearer = NULL; g_assert (profile_id != MM_3GPP_PROFILE_ID_UNKNOWN); g_object_get (self, MM_IFACE_MODEM_BEARER_LIST, &bearer_list, NULL); if (bearer_list) bearer = mm_bearer_list_find_by_profile_id (bearer_list, profile_id); /* If a bearer is found reporting the profile id we're targeting to use, * it means we have a known connected bearer, and we must abort the * operation right away. */ if (bearer) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_CONNECTED, "Cannot use profile %d: found an already connected bearer", profile_id); return FALSE; } return TRUE; } /*****************************************************************************/ /* Set profile (3GPP profile management interface) */ typedef enum { SET_PROFILE_STEP_FIRST, SET_PROFILE_STEP_CHECK_FORMAT, SET_PROFILE_STEP_LIST_BEFORE, SET_PROFILE_STEP_SELECT_PROFILE, SET_PROFILE_STEP_CHECK_ACTIVATED_PROFILE, SET_PROFILE_STEP_DEACTIVATE_PROFILE, SET_PROFILE_STEP_STORE_PROFILE, SET_PROFILE_STEP_LIST_AFTER, SET_PROFILE_STEP_LAST, } SetProfileStep; typedef struct { SetProfileStep step; MM3gppProfile *requested; gboolean strict; gboolean new_id; gint min_profile_id; gint max_profile_id; GEqualFunc profile_apn_cmp; MM3gppProfileCmpFlags profile_cmp_flags; gint profile_id; GList *before_list; MM3gppProfile *stored; } SetProfileContext; static void set_profile_context_free (SetProfileContext *ctx) { mm_3gpp_profile_list_free (ctx->before_list); g_clear_object (&ctx->requested); g_clear_object (&ctx->stored); g_slice_free (SetProfileContext, ctx); } MM3gppProfile * mm_iface_modem_3gpp_profile_manager_set_profile_finish (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GError **error) { return MM_3GPP_PROFILE (g_task_propagate_pointer (G_TASK (res), error)); } static void set_profile_step (GTask *task); static void profile_manager_get_profile_after_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { SetProfileContext *ctx; GError *error = NULL; ctx = g_task_get_task_data (task); ctx->stored = mm_iface_modem_3gpp_profile_manager_get_profile_finish (self, res, &error); if (!ctx->stored) { g_prefix_error (&error, "Couldn't validate update of profile '%d': ", ctx->profile_id); g_task_return_error (task, error); g_object_unref (task); return; } ctx->step++; set_profile_step (task); } static void set_profile_step_list_after (GTask *task) { MMIfaceModem3gppProfileManager *self; SetProfileContext *ctx; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); mm_iface_modem_3gpp_profile_manager_get_profile ( self, ctx->profile_id, (GAsyncReadyCallback)profile_manager_get_profile_after_ready, task); } static void profile_manager_store_profile_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { SetProfileContext *ctx; GError *error = NULL; gint profile_id; ctx = g_task_get_task_data (task); profile_id = MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->store_profile_finish (self, res, &error); if (profile_id == MM_3GPP_PROFILE_ID_UNKNOWN) { g_task_return_error (task, error); g_object_unref (task); return; } /* when creating a new profile with an unbound input profile id, store the * one received after store */ if (ctx->profile_id == MM_3GPP_PROFILE_ID_UNKNOWN) ctx->profile_id = profile_id; g_assert (ctx->profile_id == profile_id); mm_obj_dbg (self, "stored profile with id '%d'", ctx->profile_id); ctx->step++; set_profile_step (task); } static void set_profile_step_store_profile (GTask *task) { MMIfaceModem3gppProfileManager *self; SetProfileContext *ctx; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); g_assert (!ctx->stored); MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->store_profile ( self, ctx->requested, (GAsyncReadyCallback) profile_manager_store_profile_ready, task); } static void profile_manager_deactivate_profile_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { SetProfileContext *ctx; g_autoptr(GError) error = NULL; ctx = g_task_get_task_data (task); /* profile deactivation errors aren't fatal per se */ if (!MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->deactivate_profile_finish (self, res, &error)) mm_obj_dbg (self, "couldn't deactivate profile with id '%d': %s", ctx->profile_id, error->message); else mm_obj_dbg (self, "deactivated profile with id '%d'", ctx->profile_id); ctx->step++; set_profile_step (task); } static void set_profile_step_deactivate_profile (GTask *task) { MMIfaceModem3gppProfileManager *self; SetProfileContext *ctx; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); if (!MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->deactivate_profile || !MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->deactivate_profile_finish) { mm_obj_dbg (self, "skipping profile deactivation"); ctx->step++; set_profile_step (task); return; } /* This profile deactivation is EXCLUSIVELY done for those profiles that * are connected in the modem but for which we don't have any connected * bearer tracked. This covers e.g. a clean recovery of a previous daemon * crash, and is now defined as a supported step in the core logic, instead * of doing it differently in the different plugins and protocols. */ MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->deactivate_profile ( self, ctx->requested, (GAsyncReadyCallback) profile_manager_deactivate_profile_ready, task); } static void profile_manager_check_activated_profile_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { SetProfileContext *ctx; gboolean activated = TRUE; g_autoptr(GError) error = NULL; ctx = g_task_get_task_data (task); if (!MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->check_activated_profile_finish (self, res, &activated, &error)) { mm_obj_dbg (self, "couldn't check if profile '%d' is activated: %s", ctx->profile_id, error->message); ctx->step = SET_PROFILE_STEP_DEACTIVATE_PROFILE; } else if (activated) { mm_obj_dbg (self, "profile '%d' is activated", ctx->profile_id); ctx->step = SET_PROFILE_STEP_DEACTIVATE_PROFILE; } else { mm_obj_dbg (self, "profile '%d' is not activated", ctx->profile_id); ctx->step = SET_PROFILE_STEP_STORE_PROFILE; } set_profile_step (task); } static void set_profile_step_check_activated_profile (GTask *task) { MMIfaceModem3gppProfileManager *self; SetProfileContext *ctx; GError *error = NULL; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); g_assert (ctx->profile_id != MM_3GPP_PROFILE_ID_UNKNOWN); /* First, a quick check on our own bearer list. If we have a known bearer * connected using the same profile id, we fail the operation right away. */ if (!profile_manager_fail_if_connected_bearer (self, ctx->profile_id, &error)) { g_task_return_error (task, error); g_object_unref (task); return; } if (!MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->check_activated_profile || !MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->check_activated_profile_finish) { ctx->step = SET_PROFILE_STEP_DEACTIVATE_PROFILE; set_profile_step (task); return; } /* Second, an actual query to the modem, in order to trigger the profile * deactivation before we attempt to activate it again */ MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->check_activated_profile ( self, ctx->requested, (GAsyncReadyCallback) profile_manager_check_activated_profile_ready, task); } static void set_profile_step_select_profile_exact (GTask *task) { MMIfaceModem3gppProfileManager *self; SetProfileContext *ctx; GError *error = NULL; g_autoptr(MM3gppProfile) existing = NULL; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); g_assert (ctx->profile_id != MM_3GPP_PROFILE_ID_UNKNOWN); /* Look for the exact profile we want to use */ existing = mm_3gpp_profile_list_find_by_profile_id (ctx->before_list, ctx->profile_id, &error); if (!existing) { g_task_return_error (task, error); g_object_unref (task); return; } /* If the profile is 100% equal to what we require, nothing to do */ if (mm_3gpp_profile_cmp (existing, ctx->requested, ctx->profile_apn_cmp, ctx->profile_cmp_flags)) { ctx->stored = g_object_ref (existing); mm_obj_dbg (self, "reusing profile '%d'", ctx->profile_id); } else mm_obj_dbg (self, "overwriting profile '%d'", ctx->profile_id); ctx->step++; set_profile_step (task); } static void set_profile_step_select_profile_new (GTask *task) { MMIfaceModem3gppProfileManager *self; SetProfileContext *ctx; GError *error = NULL; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); g_assert (ctx->profile_id == MM_3GPP_PROFILE_ID_UNKNOWN); g_assert (ctx->strict); /* If strict set required, fail if we cannot find an empty profile id */ ctx->profile_id = mm_3gpp_profile_list_find_empty (ctx->before_list, ctx->min_profile_id, ctx->max_profile_id, &error); if (ctx->profile_id == MM_3GPP_PROFILE_ID_UNKNOWN) { g_task_return_error (task, error); g_object_unref (task); return; } /* store profile id in the requested profile */ mm_3gpp_profile_set_profile_id (ctx->requested, ctx->profile_id); mm_obj_dbg (self, "creating profile '%d'", ctx->profile_id); ctx->step++; set_profile_step (task); } static void set_profile_step_select_profile_best (GTask *task) { MMIfaceModem3gppProfileManager *self; SetProfileContext *ctx; gboolean overwritten = FALSE; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); g_assert (ctx->profile_id == MM_3GPP_PROFILE_ID_UNKNOWN); g_assert (!ctx->strict); ctx->profile_id = mm_3gpp_profile_list_find_best (ctx->before_list, ctx->requested, ctx->profile_apn_cmp, ctx->profile_cmp_flags, ctx->min_profile_id, ctx->max_profile_id, self, &ctx->stored, &overwritten); /* store profile id in the requested profile */ mm_3gpp_profile_set_profile_id (ctx->requested, ctx->profile_id); /* If we're reusing an already existing profile, we're done at this * point, no need to create a new one */ if (ctx->stored) mm_obj_dbg (self, "reusing profile '%d'", ctx->profile_id); else if (overwritten) mm_obj_dbg (self, "overwriting profile '%d'", ctx->profile_id); ctx->step++; set_profile_step (task); } static void profile_manager_list_profiles_before_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { SetProfileContext *ctx; g_autoptr(GError) error = NULL; ctx = g_task_get_task_data (task); if (!mm_iface_modem_3gpp_profile_manager_list_profiles_finish (self, res, &ctx->before_list, &error)) mm_obj_dbg (self, "failed checking currently defined contexts: %s", error->message); ctx->step++; set_profile_step (task); } static void set_profile_step_list_before (GTask *task) { MMIfaceModem3gppProfileManager *self; self = g_task_get_source_object (task); mm_iface_modem_3gpp_profile_manager_list_profiles ( self, (GAsyncReadyCallback)profile_manager_list_profiles_before_ready, task); } static void set_profile_check_format_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { SetProfileContext *ctx; ctx = g_task_get_task_data (task); if (!MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->check_format_finish ( self, res, &ctx->new_id, &ctx->min_profile_id, &ctx->max_profile_id, &ctx->profile_apn_cmp, &ctx->profile_cmp_flags, NULL)) { ctx->min_profile_id = 1; ctx->max_profile_id = G_MAXINT-1; mm_obj_dbg (self, "unknown context definition format; using defaults: minimum %d, maximum %d", ctx->min_profile_id, ctx->max_profile_id); } else mm_obj_dbg (self, "context definition format: minimum %d, maximum %d", ctx->min_profile_id, ctx->max_profile_id); ctx->step++; set_profile_step (task); } static void set_profile_step_check_format (GTask *task) { MMIfaceModem3gppProfileManager *self; SetProfileContext *ctx; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->check_format ( self, mm_3gpp_profile_get_ip_type (ctx->requested), (GAsyncReadyCallback)set_profile_check_format_ready, task); } static void set_profile_step (GTask *task) { MMIfaceModem3gppProfileManager *self; SetProfileContext *ctx; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); switch (ctx->step) { case SET_PROFILE_STEP_FIRST: ctx->step++; /* Fall through */ case SET_PROFILE_STEP_CHECK_FORMAT: mm_obj_dbg (self, "set profile state (%d/%d): check format", ctx->step, SET_PROFILE_STEP_LAST); set_profile_step_check_format (task); return; case SET_PROFILE_STEP_LIST_BEFORE: mm_obj_dbg (self, "set profile state (%d/%d): list before", ctx->step, SET_PROFILE_STEP_LAST); set_profile_step_list_before (task); return; case SET_PROFILE_STEP_SELECT_PROFILE: if (ctx->profile_id != MM_3GPP_PROFILE_ID_UNKNOWN) { mm_obj_dbg (self, "set profile state (%d/%d): select profile (exact)", ctx->step, SET_PROFILE_STEP_LAST); set_profile_step_select_profile_exact (task); return; } if (!ctx->strict) { mm_obj_dbg (self, "set profile state (%d/%d): select profile (best)", ctx->step, SET_PROFILE_STEP_LAST); set_profile_step_select_profile_best (task); return; } if (ctx->new_id) { mm_obj_dbg (self, "set profile state (%d/%d): select profile (new)", ctx->step, SET_PROFILE_STEP_LAST); set_profile_step_select_profile_new (task); return; } mm_obj_dbg (self, "set profile state (%d/%d): select profile (none)", ctx->step, SET_PROFILE_STEP_LAST); ctx->step++; /* Fall through */ case SET_PROFILE_STEP_CHECK_ACTIVATED_PROFILE: /* If the modem/protocol doesn't allow preselecting the profile id of * a new profile we're going to create, then we won't have a profile id * set at this point. If so, just skip this step. */ if (ctx->profile_id != MM_3GPP_PROFILE_ID_UNKNOWN) { mm_obj_dbg (self, "set profile state (%d/%d): check activated profile", ctx->step, SET_PROFILE_STEP_LAST); set_profile_step_check_activated_profile (task); return; } ctx->step++; /* Fall through */ case SET_PROFILE_STEP_DEACTIVATE_PROFILE: /* If the modem/protocol doesn't allow preselecting the profile id of * a new profile we're going to create, then we won't have a profile id * set at this point. If so, just skip this step. */ if (ctx->profile_id != MM_3GPP_PROFILE_ID_UNKNOWN) { mm_obj_dbg (self, "set profile state (%d/%d): deactivate profile", ctx->step, SET_PROFILE_STEP_LAST); set_profile_step_deactivate_profile (task); return; } ctx->step++; /* Fall through */ case SET_PROFILE_STEP_STORE_PROFILE: /* if we're reusing an already existing profile, we can jump * to the last step now, there is no need to store any update */ if (ctx->stored) { g_assert (ctx->profile_id != MM_3GPP_PROFILE_ID_UNKNOWN); mm_obj_dbg (self, "set profile state (%d/%d): profile already stored", ctx->step, SET_PROFILE_STEP_LAST); ctx->step = SET_PROFILE_STEP_LAST; set_profile_step (task); return; } mm_obj_dbg (self, "set profile state (%d/%d): store profile", ctx->step, SET_PROFILE_STEP_LAST); set_profile_step_store_profile (task); return; case SET_PROFILE_STEP_LIST_AFTER: mm_obj_dbg (self, "set profile state (%d/%d): list after", ctx->step, SET_PROFILE_STEP_LAST); set_profile_step_list_after (task); return; case SET_PROFILE_STEP_LAST: mm_obj_dbg (self, "set profile state (%d/%d): all done", ctx->step, SET_PROFILE_STEP_LAST); g_assert (ctx->stored); g_task_return_pointer (task, g_steal_pointer (&ctx->stored), g_object_unref); g_object_unref (task); return; default: g_assert_not_reached (); } } void mm_iface_modem_3gpp_profile_manager_set_profile (MMIfaceModem3gppProfileManager *self, MM3gppProfile *requested, gboolean strict, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; SetProfileContext *ctx; MMBearerIpFamily ip_family; task = g_task_new (self, NULL, callback, user_data); ctx = g_slice_new0 (SetProfileContext); ctx->step = SET_PROFILE_STEP_FIRST; ctx->requested = g_object_ref (requested); ctx->strict = strict; ctx->profile_id = mm_3gpp_profile_get_profile_id (requested); g_task_set_task_data (task, ctx, (GDestroyNotify)set_profile_context_free); /* normalize IP family right away */ ip_family = mm_3gpp_profile_get_ip_type (requested); mm_3gpp_normalize_ip_family (&ip_family); mm_3gpp_profile_set_ip_type (requested, ip_family); set_profile_step (task); } /*****************************************************************************/ MM3gppProfile * mm_iface_modem_3gpp_profile_manager_get_profile_finish (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GError **error) { return MM_3GPP_PROFILE (g_task_propagate_pointer (G_TASK (res), error)); } static void get_profile_list_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { GError *error = NULL; GList *profiles = NULL; gint profile_id; MM3gppProfile *profile; profile_id = GPOINTER_TO_INT (g_task_get_task_data (task)); if (!MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->list_profiles_finish (self, res, &profiles, &error)) { g_task_return_error (task, error); g_object_unref (task); return; } profile = mm_3gpp_profile_list_find_by_profile_id (profiles, profile_id, &error); mm_3gpp_profile_list_free (profiles); if (!profile) { g_task_return_error (task, error); g_object_unref (task); return; } g_task_return_pointer (task, profile, g_object_unref); g_object_unref (task); } static void get_profile_single_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { GError *error = NULL; MM3gppProfile *profile; profile = MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->get_profile_finish (self, res, &error); if (!profile) g_task_return_error (task, error); else g_task_return_pointer (task, profile, g_object_unref); g_object_unref (task); } void mm_iface_modem_3gpp_profile_manager_get_profile (MMIfaceModem3gppProfileManager *self, gint profile_id, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; task = g_task_new (self, NULL, callback, user_data); if (MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->get_profile && MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->get_profile_finish) { MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->get_profile (self, profile_id, (GAsyncReadyCallback)get_profile_single_ready, task); return; } /* If there is no way to query one single profile, query all and filter */ g_task_set_task_data (task, GINT_TO_POINTER (profile_id), NULL); mm_iface_modem_3gpp_profile_manager_list_profiles (self, (GAsyncReadyCallback)get_profile_list_ready, task); } /*****************************************************************************/ typedef struct { GList *profiles; } ListProfilesContext; static void list_profiles_context_free (ListProfilesContext *ctx) { mm_3gpp_profile_list_free (ctx->profiles); g_slice_free (ListProfilesContext, ctx); } gboolean mm_iface_modem_3gpp_profile_manager_list_profiles_finish (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GList **out_profiles, GError **error) { ListProfilesContext *ctx; if (!g_task_propagate_boolean (G_TASK (res), error)) return FALSE; ctx = g_task_get_task_data (G_TASK (res)); if (out_profiles) *out_profiles = g_steal_pointer (&ctx->profiles); return TRUE; } static void internal_list_profiles_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { ListProfilesContext *ctx; GError *error = NULL; ctx = g_slice_new0 (ListProfilesContext); g_task_set_task_data (task, ctx, (GDestroyNotify) list_profiles_context_free); if (!MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->list_profiles_finish (self, res, &ctx->profiles, &error)) g_task_return_error (task, error); else g_task_return_boolean (task, TRUE); g_object_unref (task); } void mm_iface_modem_3gpp_profile_manager_list_profiles (MMIfaceModem3gppProfileManager *self, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; task = g_task_new (self, NULL, callback, user_data); /* Internal calls to the list profile logic may be performed even if the 3GPP Profile Manager * interface is not exposed in DBus, therefore, make sure this logic exits cleanly if there * is no support for listing profiles */ if (!MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->list_profiles || !MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->list_profiles_finish) { g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Listing profiles is unsupported"); g_object_unref (task); return; } MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->list_profiles ( MM_IFACE_MODEM_3GPP_PROFILE_MANAGER (self), (GAsyncReadyCallback)internal_list_profiles_ready, task); } /*****************************************************************************/ typedef struct { MmGdbusModem3gppProfileManager *skeleton; GDBusMethodInvocation *invocation; MMIfaceModem3gppProfileManager *self; } HandleListContext; static void handle_list_context_free (HandleListContext *ctx) { g_object_unref (ctx->skeleton); g_object_unref (ctx->invocation); g_object_unref (ctx->self); g_slice_free (HandleListContext, ctx); } static void list_profiles_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, HandleListContext *ctx) { GVariantBuilder builder; GError *error = NULL; GList *profiles = NULL; GList *l; if (!mm_iface_modem_3gpp_profile_manager_list_profiles_finish (self, res, &profiles, &error)) { g_dbus_method_invocation_take_error (ctx->invocation, error); handle_list_context_free (ctx); return; } /* Build array of dicts */ g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}")); for (l = profiles; l; l = g_list_next (l)) { g_autoptr(GVariant) dict = NULL; dict = mm_3gpp_profile_get_dictionary (MM_3GPP_PROFILE (l->data)); g_variant_builder_add_value (&builder, dict); } mm_gdbus_modem3gpp_profile_manager_complete_list (ctx->skeleton, ctx->invocation, g_variant_builder_end (&builder)); handle_list_context_free (ctx); mm_3gpp_profile_list_free (profiles); } static void handle_list_auth_ready (MMBaseModem *self, GAsyncResult *res, HandleListContext *ctx) { GError *error = NULL; if (!mm_base_modem_authorize_finish (self, res, &error)) { g_dbus_method_invocation_take_error (ctx->invocation, error); handle_list_context_free (ctx); return; } if (mm_iface_modem_abort_invocation_if_state_not_reached (MM_IFACE_MODEM (self), ctx->invocation, MM_MODEM_STATE_ENABLED)) { handle_list_context_free (ctx); return; } /* Don't call the class callback directly, use the common helper method * that is also used by other internal operations. */ mm_iface_modem_3gpp_profile_manager_list_profiles ( MM_IFACE_MODEM_3GPP_PROFILE_MANAGER (self), (GAsyncReadyCallback)list_profiles_ready, ctx); } static gboolean handle_list (MmGdbusModem3gppProfileManager *skeleton, GDBusMethodInvocation *invocation, MMIfaceModem3gppProfileManager *self) { HandleListContext *ctx; ctx = g_slice_new0 (HandleListContext); ctx->skeleton = g_object_ref (skeleton); ctx->invocation = g_object_ref (invocation); ctx->self = g_object_ref (self); mm_base_modem_authorize (MM_BASE_MODEM (self), invocation, MM_AUTHORIZATION_DEVICE_CONTROL, (GAsyncReadyCallback)handle_list_auth_ready, ctx); return TRUE; } /*****************************************************************************/ typedef struct { MmGdbusModem3gppProfileManager *skeleton; GDBusMethodInvocation *invocation; GVariant *requested_dictionary; MMIfaceModem3gppProfileManager *self; } HandleSetContext; static void handle_set_context_free (HandleSetContext *ctx) { g_clear_pointer (&ctx->requested_dictionary, g_variant_unref); g_object_unref (ctx->skeleton); g_object_unref (ctx->invocation); g_object_unref (ctx->self); g_slice_free (HandleSetContext, ctx); } static void set_profile_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, HandleSetContext *ctx) { GError *error = NULL; g_autoptr(MM3gppProfile) profile_stored = NULL; profile_stored = mm_iface_modem_3gpp_profile_manager_set_profile_finish (self, res, &error); if (!profile_stored) g_dbus_method_invocation_take_error (ctx->invocation, error); else { g_autoptr(GVariant) profile_dictionary = NULL; profile_dictionary = mm_3gpp_profile_get_dictionary (profile_stored); mm_gdbus_modem3gpp_profile_manager_complete_set (ctx->skeleton, ctx->invocation, profile_dictionary); } handle_set_context_free (ctx); } static void handle_set_auth_ready (MMBaseModem *self, GAsyncResult *res, HandleSetContext *ctx) { GError *error = NULL; g_autoptr(MM3gppProfile) profile_requested = NULL; if (!mm_base_modem_authorize_finish (self, res, &error)) { g_dbus_method_invocation_take_error (ctx->invocation, error); handle_set_context_free (ctx); return; } if (mm_iface_modem_abort_invocation_if_state_not_reached (MM_IFACE_MODEM (self), ctx->invocation, MM_MODEM_STATE_ENABLED)) { handle_set_context_free (ctx); return; } if (!ctx->requested_dictionary) { g_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Missing requested profile settings"); handle_set_context_free (ctx); return; } profile_requested = mm_3gpp_profile_new_from_dictionary (ctx->requested_dictionary, &error); if (!profile_requested) { g_dbus_method_invocation_take_error (ctx->invocation, error); handle_set_context_free (ctx); return; } /* Don't call the class callback directly, use the common helper method * that is also used by other internal operations. */ mm_iface_modem_3gpp_profile_manager_set_profile ( MM_IFACE_MODEM_3GPP_PROFILE_MANAGER (self), profile_requested, TRUE, /* strict always! */ (GAsyncReadyCallback)set_profile_ready, ctx); } static gboolean handle_set (MmGdbusModem3gppProfileManager *skeleton, GDBusMethodInvocation *invocation, GVariant *requested_dictionary, MMIfaceModem3gppProfileManager *self) { HandleSetContext *ctx; ctx = g_slice_new0 (HandleSetContext); ctx->skeleton = g_object_ref (skeleton); ctx->invocation = g_object_ref (invocation); ctx->self = g_object_ref (self); ctx->requested_dictionary = requested_dictionary ? g_variant_ref (requested_dictionary) : NULL; mm_base_modem_authorize (MM_BASE_MODEM (self), invocation, MM_AUTHORIZATION_DEVICE_CONTROL, (GAsyncReadyCallback)handle_set_auth_ready, ctx); return TRUE; } /*****************************************************************************/ typedef struct { MmGdbusModem3gppProfileManager *skeleton; GDBusMethodInvocation *invocation; GVariant *dictionary; MMIfaceModem3gppProfileManager *self; } HandleDeleteContext; static void handle_delete_context_free (HandleDeleteContext *ctx) { g_clear_pointer (&ctx->dictionary, g_variant_unref); g_object_unref (ctx->skeleton); g_object_unref (ctx->invocation); g_object_unref (ctx->self); g_slice_free (HandleDeleteContext, ctx); } static void delete_profile_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, HandleDeleteContext *ctx) { GError *error = NULL; if (!MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->delete_profile_finish (self, res, &error)) g_dbus_method_invocation_take_error (ctx->invocation, error); else mm_gdbus_modem3gpp_profile_manager_complete_delete (ctx->skeleton, ctx->invocation); handle_delete_context_free (ctx); } static void handle_delete_auth_ready (MMBaseModem *self, GAsyncResult *res, HandleDeleteContext *ctx) { gint profile_id; GError *error = NULL; g_autoptr(MM3gppProfile) profile = NULL; if (!mm_base_modem_authorize_finish (self, res, &error)) { g_dbus_method_invocation_take_error (ctx->invocation, error); handle_delete_context_free (ctx); return; } if (mm_iface_modem_abort_invocation_if_state_not_reached (MM_IFACE_MODEM (self), ctx->invocation, MM_MODEM_STATE_ENABLED)) { handle_delete_context_free (ctx); return; } if (!MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->delete_profile || !MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->delete_profile_finish) { g_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Deleting profiles is not supported"); handle_delete_context_free (ctx); return; } if (!ctx->dictionary) { g_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Missing profile settings"); handle_delete_context_free (ctx); return; } profile = mm_3gpp_profile_new_from_dictionary (ctx->dictionary, &error); if (!profile) { g_dbus_method_invocation_take_error (ctx->invocation, error); handle_delete_context_free (ctx); return; } profile_id = mm_3gpp_profile_get_profile_id (profile); if (profile_id == MM_3GPP_PROFILE_ID_UNKNOWN) { g_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Missing 'profile-id' in profile settings"); handle_delete_context_free (ctx); return; } if (!profile_manager_fail_if_connected_bearer (MM_IFACE_MODEM_3GPP_PROFILE_MANAGER (self), profile_id, &error)) { g_dbus_method_invocation_take_error (ctx->invocation, error); handle_delete_context_free (ctx); return; } MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->delete_profile ( MM_IFACE_MODEM_3GPP_PROFILE_MANAGER (self), profile, (GAsyncReadyCallback)delete_profile_ready, ctx); } static gboolean handle_delete (MmGdbusModem3gppProfileManager *skeleton, GDBusMethodInvocation *invocation, GVariant *dictionary, MMIfaceModem3gppProfileManager *self) { HandleDeleteContext *ctx; ctx = g_slice_new0 (HandleDeleteContext); ctx->skeleton = g_object_ref (skeleton); ctx->invocation = g_object_ref (invocation); ctx->self = g_object_ref (self); ctx->dictionary = g_variant_ref (dictionary); mm_base_modem_authorize (MM_BASE_MODEM (self), invocation, MM_AUTHORIZATION_DEVICE_CONTROL, (GAsyncReadyCallback)handle_delete_auth_ready, ctx); return TRUE; } /*****************************************************************************/ typedef struct _DisablingContext DisablingContext; static void interface_disabling_step (GTask *task); typedef enum { DISABLING_STEP_FIRST, DISABLING_STEP_DISABLE_UNSOLICITED_EVENTS, DISABLING_STEP_CLEANUP_UNSOLICITED_EVENTS, DISABLING_STEP_LAST } DisablingStep; struct _DisablingContext { DisablingStep step; MmGdbusModem3gppProfileManager *skeleton; }; static void disabling_context_free (DisablingContext *ctx) { g_clear_object (&ctx->skeleton); g_slice_free (DisablingContext, ctx); } gboolean mm_iface_modem_3gpp_profile_manager_disable_finish (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GError **error) { return g_task_propagate_boolean (G_TASK (res), error); } static void disable_unsolicited_events_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { DisablingContext *ctx; g_autoptr(GError) error = NULL; MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->disable_unsolicited_events_finish (self, res, &error); if (error) { /* This error shouldn't be treated as critical */ mm_obj_dbg (self, "couldn't disable unsolicited profile management events: %s", error->message); } /* Go on to next step */ ctx = g_task_get_task_data (task); ctx->step++; interface_disabling_step (task); } static void cleanup_unsolicited_events_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { DisablingContext *ctx; g_autoptr(GError) error = NULL; MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->cleanup_unsolicited_events_finish (self, res, &error); if (error) { /* This error shouldn't be treated as critical */ mm_obj_dbg (self, "couldn't cleanup unsolicited profile management events: %s", error->message); } /* Go on to next step */ ctx = g_task_get_task_data (task); ctx->step++; interface_disabling_step (task); } static void interface_disabling_step (GTask *task) { MMIfaceModem3gppProfileManager *self; DisablingContext *ctx; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); switch (ctx->step) { case DISABLING_STEP_FIRST: ctx->step++; /* fall through */ case DISABLING_STEP_DISABLE_UNSOLICITED_EVENTS: if (MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->disable_unsolicited_events && MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->disable_unsolicited_events_finish) { MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->disable_unsolicited_events ( self, (GAsyncReadyCallback)disable_unsolicited_events_ready, task); return; } ctx->step++; /* fall through */ case DISABLING_STEP_CLEANUP_UNSOLICITED_EVENTS: if (MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->cleanup_unsolicited_events && MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->cleanup_unsolicited_events_finish) { MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->cleanup_unsolicited_events ( self, (GAsyncReadyCallback)cleanup_unsolicited_events_ready, task); return; } ctx->step++; /* fall through */ case DISABLING_STEP_LAST: /* We are done without errors! */ g_task_return_boolean (task, TRUE); g_object_unref (task); return; default: break; } g_assert_not_reached (); } void mm_iface_modem_3gpp_profile_manager_disable (MMIfaceModem3gppProfileManager *self, GAsyncReadyCallback callback, gpointer user_data) { DisablingContext *ctx; GTask *task; ctx = g_slice_new0 (DisablingContext); ctx->step = DISABLING_STEP_FIRST; task = g_task_new (self, NULL, callback, user_data); g_task_set_task_data (task, ctx, (GDestroyNotify)disabling_context_free); g_object_get (self, MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_DBUS_SKELETON, &ctx->skeleton, NULL); if (!ctx->skeleton) { g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't get interface skeleton"); g_object_unref (task); return; } interface_disabling_step (task); } /*****************************************************************************/ typedef struct _EnablingContext EnablingContext; static void interface_enabling_step (GTask *task); typedef enum { ENABLING_STEP_FIRST, ENABLING_STEP_SETUP_UNSOLICITED_EVENTS, ENABLING_STEP_ENABLE_UNSOLICITED_EVENTS, ENABLING_STEP_LAST } EnablingStep; struct _EnablingContext { EnablingStep step; MmGdbusModem3gppProfileManager *skeleton; }; static void enabling_context_free (EnablingContext *ctx) { g_clear_object (&ctx->skeleton); g_slice_free (EnablingContext, ctx); } gboolean mm_iface_modem_3gpp_profile_manager_enable_finish (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GError **error) { return g_task_propagate_boolean (G_TASK (res), error); } static void setup_unsolicited_events_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { EnablingContext *ctx; g_autoptr(GError) error = NULL; MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->setup_unsolicited_events_finish (self, res, &error); if (error) { /* This error shouldn't be treated as critical */ mm_obj_dbg (self, "couldn't setup unsolicited profile management events: %s", error->message); } /* Go on to next step */ ctx = g_task_get_task_data (task); ctx->step++; interface_enabling_step (task); } static void enable_unsolicited_events_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { EnablingContext *ctx; g_autoptr(GError) error = NULL; MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->enable_unsolicited_events_finish (self, res, &error); if (error) { /* This error shouldn't be treated as critical */ mm_obj_dbg (self, "couldn't enable unsolicited profile management events: %s", error->message); } /* Go on to next step */ ctx = g_task_get_task_data (task); ctx->step++; interface_enabling_step (task); } static void interface_enabling_step (GTask *task) { MMIfaceModem3gppProfileManager *self; EnablingContext *ctx; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); switch (ctx->step) { case ENABLING_STEP_FIRST: ctx->step++; /* fall through */ case ENABLING_STEP_SETUP_UNSOLICITED_EVENTS: if (MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->setup_unsolicited_events && MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->setup_unsolicited_events_finish) { MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->setup_unsolicited_events ( self, (GAsyncReadyCallback)setup_unsolicited_events_ready, task); return; } ctx->step++; /* fall through */ case ENABLING_STEP_ENABLE_UNSOLICITED_EVENTS: if (MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->enable_unsolicited_events && MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->enable_unsolicited_events_finish) { MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->enable_unsolicited_events ( self, (GAsyncReadyCallback)enable_unsolicited_events_ready, task); return; } ctx->step++; /* fall through */ case ENABLING_STEP_LAST: /* We are done without errors! */ g_task_return_boolean (task, TRUE); g_object_unref (task); return; default: break; } g_assert_not_reached (); } void mm_iface_modem_3gpp_profile_manager_enable (MMIfaceModem3gppProfileManager *self, GAsyncReadyCallback callback, gpointer user_data) { EnablingContext *ctx; GTask *task; ctx = g_slice_new0 (EnablingContext); ctx->step = ENABLING_STEP_FIRST; task = g_task_new (self, NULL, callback, user_data); g_task_set_task_data (task, ctx, (GDestroyNotify)enabling_context_free); g_object_get (self, MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_DBUS_SKELETON, &ctx->skeleton, NULL); if (!ctx->skeleton) { g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't get interface skeleton"); g_object_unref (task); return; } interface_enabling_step (task); } /*****************************************************************************/ typedef struct _InitializationContext InitializationContext; static void interface_initialization_step (GTask *task); typedef enum { INITIALIZATION_STEP_FIRST, INITIALIZATION_STEP_CHECK_SUPPORT, INITIALIZATION_STEP_FAIL_IF_UNSUPPORTED, INITIALIZATION_STEP_LAST } InitializationStep; struct _InitializationContext { MmGdbusModem3gppProfileManager *skeleton; InitializationStep step; }; static void initialization_context_free (InitializationContext *ctx) { g_clear_object (&ctx->skeleton); g_slice_free (InitializationContext, ctx); } gboolean mm_iface_modem_3gpp_profile_manager_initialize_finish (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GError **error) { return g_task_propagate_boolean (G_TASK (res), error); } static void check_support_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { InitializationContext *ctx; g_autoptr(GError) error = NULL; if (!MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->check_support_finish (self, res, &error)) { if (error) { /* This error shouldn't be treated as critical */ mm_obj_dbg (self, "profile management support check failed: %s", error->message); } } else { /* profile management is supported! */ g_object_set_qdata (G_OBJECT (self), supported_quark, GUINT_TO_POINTER (TRUE)); } /* Go on to next step */ ctx = g_task_get_task_data (task); ctx->step++; interface_initialization_step (task); } static void profile_manager_list_profiles_check_ready (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, GTask *task) { InitializationContext *ctx; g_autoptr(GError) error = NULL; ctx = g_task_get_task_data (task); if (!mm_iface_modem_3gpp_profile_manager_list_profiles_finish (self, res, NULL, &error)) mm_obj_dbg (self, "profile management support check failed: couldn't load profile list: %s", error->message); else { /* profile management is supported! */ g_object_set_qdata (G_OBJECT (self), supported_quark, GUINT_TO_POINTER (TRUE)); } ctx->step++; interface_initialization_step (task); } static void interface_initialization_step (GTask *task) { MMIfaceModem3gppProfileManager *self; InitializationContext *ctx; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); switch (ctx->step) { case INITIALIZATION_STEP_FIRST: /* Setup quarks if we didn't do it before */ if (G_UNLIKELY (!support_checked_quark)) support_checked_quark = (g_quark_from_static_string (SUPPORT_CHECKED_TAG)); if (G_UNLIKELY (!supported_quark)) supported_quark = (g_quark_from_static_string (SUPPORTED_TAG)); ctx->step++; /* fall through */ case INITIALIZATION_STEP_CHECK_SUPPORT: if (!GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (self), support_checked_quark))) { /* Set the checked flag so that we don't run it again */ g_object_set_qdata (G_OBJECT (self), support_checked_quark, GUINT_TO_POINTER (TRUE)); /* Initially, assume we don't support it */ g_object_set_qdata (G_OBJECT (self), supported_quark, GUINT_TO_POINTER (FALSE)); if (MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->check_support && MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->check_support_finish) { MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_GET_INTERFACE (self)->check_support ( self, (GAsyncReadyCallback)check_support_ready, task); return; } /* If there is no implementation to check support, try to query the list * explicitly; it may be the case that there is no other way to check for * support. */ mm_iface_modem_3gpp_profile_manager_list_profiles ( self, (GAsyncReadyCallback)profile_manager_list_profiles_check_ready, task); return; } ctx->step++; /* fall through */ case INITIALIZATION_STEP_FAIL_IF_UNSUPPORTED: if (!GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (self), supported_quark))) { g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Profile management not supported"); g_object_unref (task); return; } ctx->step++; /* fall through */ case INITIALIZATION_STEP_LAST: /* We are done without errors! */ /* Handle method invocations */ g_object_connect (ctx->skeleton, "signal::handle-list", G_CALLBACK (handle_list), self, "signal::handle-set", G_CALLBACK (handle_set), self, "signal::handle-delete", G_CALLBACK (handle_delete), self, NULL); /* Finally, export the new interface */ mm_gdbus_object_skeleton_set_modem3gpp_profile_manager (MM_GDBUS_OBJECT_SKELETON (self), MM_GDBUS_MODEM3GPP_PROFILE_MANAGER (ctx->skeleton)); g_task_return_boolean (task, TRUE); g_object_unref (task); return; default: break; } g_assert_not_reached (); } void mm_iface_modem_3gpp_profile_manager_initialize (MMIfaceModem3gppProfileManager *self, GAsyncReadyCallback callback, gpointer user_data) { InitializationContext *ctx; MmGdbusModem3gppProfileManager *skeleton = NULL; GTask *task; /* Did we already create it? */ g_object_get (self, MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_DBUS_SKELETON, &skeleton, NULL); if (!skeleton) { skeleton = mm_gdbus_modem3gpp_profile_manager_skeleton_new (); g_object_set (self, MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_DBUS_SKELETON, skeleton, NULL); } /* Perform async initialization here */ ctx = g_slice_new0 (InitializationContext); ctx->step = INITIALIZATION_STEP_FIRST; ctx->skeleton = skeleton; task = g_task_new (self, NULL, callback, user_data); g_task_set_task_data (task, ctx, (GDestroyNotify)initialization_context_free); interface_initialization_step (task); } void mm_iface_modem_3gpp_profile_manager_shutdown (MMIfaceModem3gppProfileManager *self) { /* Unexport DBus interface and remove the skeleton */ mm_gdbus_object_skeleton_set_modem3gpp_profile_manager (MM_GDBUS_OBJECT_SKELETON (self), NULL); g_object_set (self, MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_DBUS_SKELETON, NULL, NULL); } /*****************************************************************************/ static void iface_modem_3gpp_profile_manager_init (gpointer g_iface) { static gboolean initialized = FALSE; if (initialized) return; /* Properties */ g_object_interface_install_property (g_iface, g_param_spec_object (MM_IFACE_MODEM_3GPP_PROFILE_MANAGER_DBUS_SKELETON, "3GPP Profile Manager DBus skeleton", "DBus skeleton for the 3GPP Profile Manager interface", MM_GDBUS_TYPE_MODEM3GPP_PROFILE_MANAGER_SKELETON, G_PARAM_READWRITE)); initialized = TRUE; } GType mm_iface_modem_3gpp_profile_manager_get_type (void) { static GType iface_modem_3gpp_profile_manager_type = 0; if (!G_UNLIKELY (iface_modem_3gpp_profile_manager_type)) { static const GTypeInfo info = { sizeof (MMIfaceModem3gppProfileManager), /* class_size */ iface_modem_3gpp_profile_manager_init, /* base_init */ NULL, /* base_finalize */ }; iface_modem_3gpp_profile_manager_type = g_type_register_static (G_TYPE_INTERFACE, "MMIfaceModem3gppProfileManager", &info, 0); g_type_interface_add_prerequisite (iface_modem_3gpp_profile_manager_type, MM_TYPE_IFACE_MODEM_3GPP); } return iface_modem_3gpp_profile_manager_type; }