| /* -*- 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) 2012 Google, Inc. |
| * Copyright (C) 2012 Lanedo GmbH |
| * Copyright (C) 2012-2019 Aleksander Morgado <aleksander@aleksander.es> |
| */ |
| |
| #include <ModemManager.h> |
| #define _LIBMM_INSIDE_MM |
| #include <libmm-glib.h> |
| |
| #include "mm-iface-modem.h" |
| #include "mm-iface-modem-location.h" |
| #include "mm-log-object.h" |
| #include "mm-error-helpers.h" |
| #include "mm-modem-helpers.h" |
| |
| #define MM_LOCATION_GPS_REFRESH_TIME_SECS 30 |
| |
| #define LOCATION_CONTEXT_TAG "location-context-tag" |
| |
| static GQuark location_context_quark; |
| |
| G_DEFINE_INTERFACE (MMIfaceModemLocation, mm_iface_modem_location, MM_TYPE_IFACE_MODEM) |
| |
| /*****************************************************************************/ |
| |
| void |
| mm_iface_modem_location_bind_simple_status (MMIfaceModemLocation *self, |
| MMSimpleStatus *status) |
| { |
| } |
| |
| /*****************************************************************************/ |
| |
| typedef struct { |
| /* 3GPP location */ |
| MMLocation3gpp *location_3gpp; |
| /* GPS location */ |
| time_t location_gps_nmea_last_time; |
| MMLocationGpsNmea *location_gps_nmea; |
| time_t location_gps_raw_last_time; |
| MMLocationGpsRaw *location_gps_raw; |
| /* CDMA BS location */ |
| MMLocationCdmaBs *location_cdma_bs; |
| } LocationContext; |
| |
| static void |
| location_context_free (LocationContext *ctx) |
| { |
| if (ctx->location_3gpp) |
| g_object_unref (ctx->location_3gpp); |
| if (ctx->location_gps_nmea) |
| g_object_unref (ctx->location_gps_nmea); |
| if (ctx->location_gps_raw) |
| g_object_unref (ctx->location_gps_raw); |
| if (ctx->location_cdma_bs) |
| g_object_unref (ctx->location_cdma_bs); |
| g_free (ctx); |
| } |
| |
| static void |
| clear_location_context (MMIfaceModemLocation *self) |
| { |
| if (G_UNLIKELY (!location_context_quark)) |
| location_context_quark = (g_quark_from_static_string ( |
| LOCATION_CONTEXT_TAG)); |
| |
| /* Clear all location data */ |
| g_object_set_qdata (G_OBJECT (self), |
| location_context_quark, |
| NULL); |
| } |
| |
| static LocationContext * |
| get_location_context (MMIfaceModemLocation *self) |
| { |
| LocationContext *ctx; |
| |
| if (G_UNLIKELY (!location_context_quark)) |
| location_context_quark = (g_quark_from_static_string ( |
| LOCATION_CONTEXT_TAG)); |
| |
| ctx = g_object_get_qdata (G_OBJECT (self), location_context_quark); |
| if (!ctx) { |
| /* Create context and keep it as object data */ |
| ctx = g_new0 (LocationContext, 1); |
| |
| g_object_set_qdata_full ( |
| G_OBJECT (self), |
| location_context_quark, |
| ctx, |
| (GDestroyNotify)location_context_free); |
| } |
| |
| return ctx; |
| } |
| |
| /*****************************************************************************/ |
| |
| static GVariant * |
| build_location_dictionary (GVariant *previous, |
| MMLocation3gpp *location_3gpp, |
| MMLocationGpsNmea *location_gps_nmea, |
| MMLocationGpsRaw *location_gps_raw, |
| MMLocationCdmaBs *location_cdma_bs) |
| { |
| GVariant *location_3gpp_value = NULL; |
| GVariant *location_gps_nmea_value = NULL; |
| GVariant *location_gps_raw_value = NULL; |
| GVariant *location_cdma_bs_value = NULL; |
| GVariantBuilder builder; |
| |
| /* If a previous dictionary given, parse its values */ |
| if (previous) { |
| guint source; |
| GVariant *value; |
| GVariantIter iter; |
| |
| g_variant_iter_init (&iter, previous); |
| while (g_variant_iter_next (&iter, "{uv}", &source, &value)) { |
| switch (source) { |
| case MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI: |
| g_assert (!location_3gpp_value); |
| location_3gpp_value = value; |
| break; |
| case MM_MODEM_LOCATION_SOURCE_GPS_NMEA: |
| g_assert (!location_gps_nmea_value); |
| location_gps_nmea_value = value; |
| break; |
| case MM_MODEM_LOCATION_SOURCE_GPS_RAW: |
| g_assert (!location_gps_raw_value); |
| location_gps_raw_value = value; |
| break; |
| case MM_MODEM_LOCATION_SOURCE_CDMA_BS: |
| g_assert (!location_cdma_bs_value); |
| location_cdma_bs_value = value; |
| break; |
| case MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED: |
| g_assert_not_reached (); |
| case MM_MODEM_LOCATION_SOURCE_AGPS_MSA: |
| g_assert_not_reached (); |
| case MM_MODEM_LOCATION_SOURCE_AGPS_MSB: |
| g_assert_not_reached (); |
| default: |
| g_warn_if_reached (); |
| g_variant_unref (value); |
| break; |
| } |
| } |
| } |
| |
| /* Build the new one */ |
| g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{uv}")); |
| |
| /* If a new one given, use it */ |
| if (location_3gpp) { |
| if (location_3gpp_value) |
| g_variant_unref (location_3gpp_value); |
| location_3gpp_value = mm_location_3gpp_get_string_variant (location_3gpp); |
| } |
| |
| if (location_3gpp_value) { |
| g_assert (!g_variant_is_floating (location_3gpp_value)); |
| g_variant_builder_add (&builder, |
| "{uv}", |
| MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI, |
| location_3gpp_value); |
| g_variant_unref (location_3gpp_value); |
| } |
| |
| /* If a new one given, use it */ |
| if (location_gps_nmea) { |
| if (location_gps_nmea_value) |
| g_variant_unref (location_gps_nmea_value); |
| location_gps_nmea_value = mm_location_gps_nmea_get_string_variant (location_gps_nmea); |
| } |
| |
| if (location_gps_nmea_value) { |
| g_assert (!g_variant_is_floating (location_gps_nmea_value)); |
| g_variant_builder_add (&builder, |
| "{uv}", |
| MM_MODEM_LOCATION_SOURCE_GPS_NMEA, |
| location_gps_nmea_value); |
| g_variant_unref (location_gps_nmea_value); |
| } |
| |
| /* If a new one given, use it */ |
| if (location_gps_raw) { |
| if (location_gps_raw_value) |
| g_variant_unref (location_gps_raw_value); |
| location_gps_raw_value = mm_location_gps_raw_get_dictionary (location_gps_raw); |
| } |
| |
| if (location_gps_raw_value) { |
| g_assert (!g_variant_is_floating (location_gps_raw_value)); |
| g_variant_builder_add (&builder, |
| "{uv}", |
| MM_MODEM_LOCATION_SOURCE_GPS_RAW, |
| location_gps_raw_value); |
| g_variant_unref (location_gps_raw_value); |
| } |
| |
| /* If a new one given, use it */ |
| if (location_cdma_bs) { |
| if (location_cdma_bs_value) |
| g_variant_unref (location_cdma_bs_value); |
| location_cdma_bs_value = mm_location_cdma_bs_get_dictionary (location_cdma_bs); |
| } |
| |
| if (location_cdma_bs_value) { |
| g_assert (!g_variant_is_floating (location_cdma_bs_value)); |
| g_variant_builder_add (&builder, |
| "{uv}", |
| MM_MODEM_LOCATION_SOURCE_CDMA_BS, |
| location_cdma_bs_value); |
| g_variant_unref (location_cdma_bs_value); |
| } |
| |
| return g_variant_builder_end (&builder); |
| } |
| |
| /*****************************************************************************/ |
| |
| static void |
| notify_gps_location_update (MMIfaceModemLocation *self, |
| MmGdbusModemLocation *skeleton, |
| MMLocationGpsNmea *location_gps_nmea, |
| MMLocationGpsRaw *location_gps_raw) |
| { |
| mm_obj_dbg (self, "GPS location updated"); |
| |
| /* We only update the property if we are supposed to signal |
| * location */ |
| if (mm_gdbus_modem_location_get_signals_location (skeleton)) |
| mm_gdbus_modem_location_set_location ( |
| skeleton, |
| build_location_dictionary (mm_gdbus_modem_location_get_location (skeleton), |
| NULL, |
| location_gps_nmea, |
| location_gps_raw, |
| NULL)); |
| } |
| |
| static void |
| location_gps_update_nmea (MMIfaceModemLocation *self, |
| const gchar *nmea_trace) |
| { |
| MmGdbusModemLocation *skeleton; |
| LocationContext *ctx; |
| gboolean update_nmea = FALSE; |
| gboolean update_raw = FALSE; |
| |
| ctx = get_location_context (self); |
| g_object_get (self, |
| MM_IFACE_MODEM_LOCATION_DBUS_SKELETON, &skeleton, |
| NULL); |
| if (!skeleton) |
| return; |
| |
| if (mm_gdbus_modem_location_get_enabled (skeleton) & MM_MODEM_LOCATION_SOURCE_GPS_NMEA) { |
| g_assert (ctx->location_gps_nmea != NULL); |
| if (mm_location_gps_nmea_add_trace (ctx->location_gps_nmea, nmea_trace) && |
| (ctx->location_gps_nmea_last_time == 0 || |
| time (NULL) - ctx->location_gps_nmea_last_time >= (glong)mm_gdbus_modem_location_get_gps_refresh_rate (skeleton))) { |
| ctx->location_gps_nmea_last_time = time (NULL); |
| update_nmea = TRUE; |
| } |
| } |
| |
| if (mm_gdbus_modem_location_get_enabled (skeleton) & MM_MODEM_LOCATION_SOURCE_GPS_RAW) { |
| g_assert (ctx->location_gps_raw != NULL); |
| if (mm_location_gps_raw_add_trace (ctx->location_gps_raw, nmea_trace) && |
| (ctx->location_gps_raw_last_time == 0 || |
| time (NULL) - ctx->location_gps_raw_last_time >= (glong)mm_gdbus_modem_location_get_gps_refresh_rate (skeleton))) { |
| ctx->location_gps_raw_last_time = time (NULL); |
| update_raw = TRUE; |
| } |
| } |
| |
| if (update_nmea || update_raw) |
| notify_gps_location_update (self, |
| skeleton, |
| update_nmea ? ctx->location_gps_nmea : NULL, |
| update_raw ? ctx->location_gps_raw : NULL); |
| |
| g_object_unref (skeleton); |
| } |
| |
| void |
| mm_iface_modem_location_gps_update (MMIfaceModemLocation *self, |
| const gchar *nmea_trace) |
| { |
| /* Helper to debug GPS location related issues. Don't depend on a real GPS |
| * fix for debugging, just use some random values to update */ |
| #if 0 |
| { |
| const gchar *prefix = NULL; |
| const gchar *lat = NULL; |
| |
| /* lat N/S just to test which one is used */ |
| if (g_str_has_prefix (nmea_trace, "$GPGGA")) { |
| prefix = "GPGGA"; |
| lat = "S"; |
| } else if (g_str_has_prefix (nmea_trace, "$GNGGA")) { |
| prefix = "GNGGA"; |
| lat = "N"; |
| } |
| |
| if (prefix && lat) { |
| g_autoptr(GString) str = NULL; |
| g_autoptr(GDateTime) now = NULL; |
| |
| mm_obj_dbg (self, "GGA trace detected: %s", nmea_trace); |
| |
| now = g_date_time_new_now_utc (); |
| str = g_string_new (""); |
| g_string_append_printf (str, |
| "$%s,%02u%02u%02u,4807.038,%s,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47", |
| prefix, |
| g_date_time_get_hour (now), |
| g_date_time_get_minute (now), |
| g_date_time_get_second (now), |
| lat); |
| location_gps_update_nmea (self, str->str); |
| return; |
| } |
| } |
| #endif |
| |
| location_gps_update_nmea (self, nmea_trace); |
| } |
| |
| /*****************************************************************************/ |
| |
| static void |
| notify_3gpp_location_update (MMIfaceModemLocation *self, |
| MmGdbusModemLocation *skeleton, |
| MMLocation3gpp *location_3gpp) |
| { |
| const gchar *operator_code; |
| |
| operator_code = mm_location_3gpp_get_operator_code (location_3gpp); |
| mm_obj_dbg (self, "3GPP location updated " |
| "(MCCMNC: '%s', location area code: '%04lX', tracking area code: '%06lX', cell ID: '%08lX')", |
| operator_code ? operator_code : "<none>", |
| mm_location_3gpp_get_location_area_code (location_3gpp), |
| mm_location_3gpp_get_tracking_area_code (location_3gpp), |
| mm_location_3gpp_get_cell_id (location_3gpp)); |
| |
| /* We only update the property if we are supposed to signal |
| * location */ |
| if (mm_gdbus_modem_location_get_signals_location (skeleton)) |
| mm_gdbus_modem_location_set_location ( |
| skeleton, |
| build_location_dictionary (mm_gdbus_modem_location_get_location (skeleton), |
| location_3gpp, |
| NULL, NULL, |
| NULL)); |
| } |
| |
| void |
| mm_iface_modem_location_3gpp_update_operator_code (MMIfaceModemLocation *self, |
| const gchar *operator_code) |
| { |
| MmGdbusModemLocation *skeleton; |
| LocationContext *ctx; |
| |
| ctx = get_location_context (self); |
| g_object_get (self, |
| MM_IFACE_MODEM_LOCATION_DBUS_SKELETON, &skeleton, |
| NULL); |
| if (!skeleton) |
| return; |
| |
| if (mm_gdbus_modem_location_get_enabled (skeleton) & MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI) { |
| guint changed = 0; |
| |
| g_assert (ctx->location_3gpp != NULL); |
| changed += mm_location_3gpp_set_operator_code (ctx->location_3gpp, |
| operator_code); |
| if (changed) |
| notify_3gpp_location_update (self, skeleton, ctx->location_3gpp); |
| } |
| |
| g_object_unref (skeleton); |
| } |
| |
| void |
| mm_iface_modem_location_3gpp_update_lac_tac_ci (MMIfaceModemLocation *self, |
| gulong location_area_code, |
| gulong tracking_area_code, |
| gulong cell_id) |
| { |
| g_autoptr(MmGdbusModemLocationSkeleton) skeleton = NULL; |
| LocationContext *ctx; |
| guint changed = 0; |
| gulong old_location_area_code; |
| gulong old_tracking_area_code; |
| gulong old_cell_id; |
| |
| g_object_get (self, |
| MM_IFACE_MODEM_LOCATION_DBUS_SKELETON, &skeleton, |
| NULL); |
| if (!skeleton || !(mm_gdbus_modem_location_get_enabled (MM_GDBUS_MODEM_LOCATION (skeleton)) & MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI)) |
| return; |
| |
| ctx = get_location_context (self); |
| g_assert (ctx->location_3gpp != NULL); |
| |
| old_location_area_code = mm_location_3gpp_get_location_area_code (ctx->location_3gpp); |
| old_tracking_area_code = mm_location_3gpp_get_tracking_area_code (ctx->location_3gpp); |
| old_cell_id = mm_location_3gpp_get_cell_id (ctx->location_3gpp); |
| |
| /* Update LAC if given, and clear TAC unless a TAC is also given */ |
| if (location_area_code) { |
| if (old_location_area_code != location_area_code) { |
| mm_obj_dbg (self, "3GPP location area code updated: '%04lX->%04lX'", old_location_area_code, location_area_code); |
| mm_location_3gpp_set_location_area_code (ctx->location_3gpp, location_area_code); |
| changed++; |
| } |
| if (!tracking_area_code) { |
| if (old_tracking_area_code != 0) { |
| mm_obj_dbg (self, "3GPP tracking area code cleared: '%06lX->%06lX'", old_tracking_area_code, tracking_area_code); |
| mm_location_3gpp_set_tracking_area_code (ctx->location_3gpp, 0); |
| changed++; |
| } |
| } |
| } |
| /* Update TAC if given, and clear LAC unless a LAC is also given */ |
| if (tracking_area_code) { |
| if (old_tracking_area_code != tracking_area_code) { |
| mm_obj_dbg (self, "3GPP tracking area code updated: '%06lX->%06lX'", old_tracking_area_code, tracking_area_code); |
| mm_location_3gpp_set_tracking_area_code (ctx->location_3gpp, tracking_area_code); |
| changed++; |
| } |
| if (!location_area_code) { |
| if (old_location_area_code != 0) { |
| mm_obj_dbg (self, "3GPP location area code cleared: '%04lX->%04lX'", old_location_area_code, location_area_code); |
| mm_location_3gpp_set_location_area_code (ctx->location_3gpp, 0); |
| changed++; |
| } |
| } |
| } |
| |
| /* Cell ID only updated if given. It is assumed that if LAC or TAC are given, CID is also given */ |
| if (cell_id && (old_cell_id != cell_id)) { |
| mm_obj_dbg (self, "3GPP cell id updated: '%08lX->%08lX'", old_cell_id, cell_id); |
| mm_location_3gpp_set_cell_id (ctx->location_3gpp, cell_id); |
| changed++; |
| } |
| |
| if (changed) |
| notify_3gpp_location_update (self, MM_GDBUS_MODEM_LOCATION (skeleton), ctx->location_3gpp); |
| } |
| |
| void |
| mm_iface_modem_location_3gpp_clear (MMIfaceModemLocation *self) |
| { |
| MmGdbusModemLocation *skeleton; |
| LocationContext *ctx; |
| |
| ctx = get_location_context (self); |
| g_object_get (self, |
| MM_IFACE_MODEM_LOCATION_DBUS_SKELETON, &skeleton, |
| NULL); |
| if (!skeleton) |
| return; |
| |
| if (mm_gdbus_modem_location_get_enabled (skeleton) & MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI) { |
| g_assert (ctx->location_3gpp != NULL); |
| if (mm_location_3gpp_reset (ctx->location_3gpp)) |
| notify_3gpp_location_update (self, skeleton, ctx->location_3gpp); |
| } |
| |
| g_object_unref (skeleton); |
| } |
| |
| /*****************************************************************************/ |
| |
| static void |
| notify_cdma_bs_location_update (MMIfaceModemLocation *self, |
| MmGdbusModemLocation *skeleton, |
| MMLocationCdmaBs *location_cdma_bs) |
| { |
| mm_obj_dbg (self, "CDMA base station location updated (longitude: '%lf', latitude: '%lf')", |
| mm_location_cdma_bs_get_longitude (location_cdma_bs), |
| mm_location_cdma_bs_get_latitude (location_cdma_bs)); |
| |
| /* We only update the property if we are supposed to signal |
| * location */ |
| if (mm_gdbus_modem_location_get_signals_location (skeleton)) |
| mm_gdbus_modem_location_set_location ( |
| skeleton, |
| build_location_dictionary (mm_gdbus_modem_location_get_location (skeleton), |
| NULL, |
| NULL, NULL, |
| location_cdma_bs)); |
| } |
| |
| void |
| mm_iface_modem_location_cdma_bs_update (MMIfaceModemLocation *self, |
| gdouble longitude, |
| gdouble latitude) |
| { |
| MmGdbusModemLocation *skeleton; |
| LocationContext *ctx; |
| |
| ctx = get_location_context (self); |
| g_object_get (self, |
| MM_IFACE_MODEM_LOCATION_DBUS_SKELETON, &skeleton, |
| NULL); |
| if (!skeleton) |
| return; |
| |
| if (mm_gdbus_modem_location_get_enabled (skeleton) & MM_MODEM_LOCATION_SOURCE_CDMA_BS) { |
| if (mm_location_cdma_bs_set (ctx->location_cdma_bs, longitude, latitude)) |
| notify_cdma_bs_location_update (self, skeleton, ctx->location_cdma_bs); |
| } |
| |
| g_object_unref (skeleton); |
| } |
| |
| void |
| mm_iface_modem_location_cdma_bs_clear (MMIfaceModemLocation *self) |
| { |
| mm_iface_modem_location_cdma_bs_update (self, |
| MM_LOCATION_LONGITUDE_UNKNOWN, |
| MM_LOCATION_LATITUDE_UNKNOWN); |
| } |
| |
| /*****************************************************************************/ |
| |
| static void |
| update_location_source_status (MMIfaceModemLocation *self, |
| MMModemLocationSource source, |
| gboolean enabled) |
| { |
| MMModemLocationSource mask; |
| MmGdbusModemLocation *skeleton = NULL; |
| LocationContext *ctx; |
| |
| g_object_get (self, |
| MM_IFACE_MODEM_LOCATION_DBUS_SKELETON, &skeleton, |
| NULL); |
| if (!skeleton) |
| return; |
| |
| /* Update status in the interface */ |
| mask = mm_gdbus_modem_location_get_enabled (skeleton); |
| if (enabled) |
| mask |= source; |
| else |
| mask &= ~source; |
| |
| /* Update status in the context */ |
| ctx = get_location_context (self); |
| |
| switch (source) { |
| case MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI: |
| if (enabled) { |
| if (!ctx->location_3gpp) |
| ctx->location_3gpp = mm_location_3gpp_new (); |
| } else |
| g_clear_object (&ctx->location_3gpp); |
| break; |
| case MM_MODEM_LOCATION_SOURCE_GPS_NMEA: |
| if (enabled) { |
| if (!ctx->location_gps_nmea) |
| ctx->location_gps_nmea = mm_location_gps_nmea_new (); |
| } else |
| g_clear_object (&ctx->location_gps_nmea); |
| break; |
| case MM_MODEM_LOCATION_SOURCE_GPS_RAW: |
| if (enabled) { |
| if (!ctx->location_gps_raw) |
| ctx->location_gps_raw = mm_location_gps_raw_new (); |
| } else |
| g_clear_object (&ctx->location_gps_raw); |
| break; |
| case MM_MODEM_LOCATION_SOURCE_CDMA_BS: |
| if (enabled) { |
| if (!ctx->location_cdma_bs) |
| ctx->location_cdma_bs = mm_location_cdma_bs_new (); |
| } else |
| g_clear_object (&ctx->location_cdma_bs); |
| break; |
| case MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED: |
| case MM_MODEM_LOCATION_SOURCE_AGPS_MSA: |
| case MM_MODEM_LOCATION_SOURCE_AGPS_MSB: |
| case MM_MODEM_LOCATION_SOURCE_NONE: |
| /* Nothing to setup in the context */ |
| default: |
| break; |
| } |
| |
| mm_gdbus_modem_location_set_enabled (skeleton, mask); |
| |
| g_object_unref (skeleton); |
| } |
| |
| /*****************************************************************************/ |
| |
| typedef struct { |
| MmGdbusModemLocation *skeleton; |
| MMModemLocationSource to_enable; |
| MMModemLocationSource to_disable; |
| MMModemLocationSource current; |
| } SetupGatheringContext; |
| |
| static void setup_gathering_step (GTask *task); |
| |
| static void |
| setup_gathering_context_free (SetupGatheringContext *ctx) |
| { |
| if (ctx->skeleton) |
| g_object_unref (ctx->skeleton); |
| g_free (ctx); |
| } |
| |
| static gboolean |
| setup_gathering_finish (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| GError **error) |
| { |
| return g_task_propagate_boolean (G_TASK (res), error); |
| } |
| |
| static void |
| enable_location_gathering_ready (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| GTask *task) |
| { |
| SetupGatheringContext *ctx; |
| GError *error = NULL; |
| |
| ctx = g_task_get_task_data (task); |
| |
| if (!MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->enable_location_gathering_finish (self, res, &error)) { |
| gchar *str; |
| |
| update_location_source_status (self, ctx->current, FALSE); |
| |
| str = mm_modem_location_source_build_string_from_mask (ctx->current); |
| g_prefix_error (&error, |
| "Couldn't enable location '%s' gathering: ", |
| str); |
| g_task_return_error (task, error); |
| g_object_unref (task); |
| g_free (str); |
| return; |
| } |
| |
| /* Keep on with next ones... */ |
| ctx->current = ctx->current << 1; |
| setup_gathering_step (task); |
| } |
| |
| static void |
| disable_location_gathering_ready (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| GTask *task) |
| { |
| SetupGatheringContext *ctx; |
| GError *error = NULL; |
| |
| ctx = g_task_get_task_data (task); |
| |
| if (!MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->disable_location_gathering_finish (self, res, &error)) { |
| gchar *str; |
| |
| /* Back to enabled then */ |
| update_location_source_status (self, ctx->current, TRUE); |
| |
| str = mm_modem_location_source_build_string_from_mask (ctx->current); |
| g_prefix_error (&error, |
| "Couldn't disable location '%s' gathering: ", |
| str); |
| g_task_return_error (task, error); |
| g_object_unref (task); |
| g_free (str); |
| return; |
| } |
| |
| /* Keep on with next ones... */ |
| ctx->current = ctx->current << 1; |
| setup_gathering_step (task); |
| } |
| |
| static void |
| setup_gathering_step (GTask *task) |
| { |
| MMIfaceModemLocation *self; |
| SetupGatheringContext *ctx; |
| |
| self = g_task_get_source_object (task); |
| ctx = g_task_get_task_data (task); |
| |
| /* Are we done? */ |
| if (ctx->to_enable == MM_MODEM_LOCATION_SOURCE_NONE && |
| ctx->to_disable == MM_MODEM_LOCATION_SOURCE_NONE) { |
| g_task_return_boolean (task, TRUE); |
| g_object_unref (task); |
| return; |
| } |
| |
| while (ctx->current <= MM_MODEM_LOCATION_SOURCE_LAST) { |
| gchar *source_str; |
| |
| if (ctx->to_enable & ctx->current) { |
| /* Remove from mask */ |
| ctx->to_enable &= ~ctx->current; |
| |
| /* We update the location source status before launching the |
| * specific actions to enable the gathering, so that we are |
| * able to get location updates while the gathering gets |
| * enabled. */ |
| update_location_source_status (self, ctx->current, TRUE); |
| |
| /* Plugins can run custom actions to enable location gathering */ |
| if (MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->enable_location_gathering && |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->enable_location_gathering_finish) { |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->enable_location_gathering ( |
| MM_IFACE_MODEM_LOCATION (self), |
| ctx->current, |
| (GAsyncReadyCallback)enable_location_gathering_ready, |
| task); |
| return; |
| } |
| |
| source_str = mm_modem_location_source_build_string_from_mask (ctx->current); |
| mm_obj_dbg (self, "enabled location '%s' gathering...", source_str); |
| g_free (source_str); |
| } else if (ctx->to_disable & ctx->current) { |
| /* Remove from mask */ |
| ctx->to_disable &= ~ctx->current; |
| |
| update_location_source_status (self, ctx->current, FALSE); |
| |
| /* Plugins can run custom actions to disable location gathering */ |
| if (MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->disable_location_gathering && |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->disable_location_gathering_finish) { |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->disable_location_gathering ( |
| MM_IFACE_MODEM_LOCATION (self), |
| ctx->current, |
| (GAsyncReadyCallback)disable_location_gathering_ready, |
| task); |
| return; |
| } |
| |
| source_str = mm_modem_location_source_build_string_from_mask (ctx->current); |
| mm_obj_dbg (self, "disabled location '%s' gathering...", source_str); |
| g_free (source_str); |
| } |
| |
| /* go on... */ |
| ctx->current = ctx->current << 1; |
| } |
| |
| /* We just need to finish now */ |
| g_assert (ctx->to_enable == MM_MODEM_LOCATION_SOURCE_NONE); |
| g_assert (ctx->to_disable == MM_MODEM_LOCATION_SOURCE_NONE); |
| setup_gathering_step (task); |
| } |
| |
| static void |
| setup_gathering (MMIfaceModemLocation *self, |
| MMModemLocationSource mask, |
| GAsyncReadyCallback callback, |
| gpointer user_data) |
| { |
| SetupGatheringContext *ctx; |
| GTask *task; |
| MMModemLocationSource currently_enabled; |
| MMModemLocationSource source; |
| gchar *str; |
| gboolean allow_gps_unmanaged_always = FALSE; |
| |
| ctx = g_new (SetupGatheringContext, 1); |
| |
| task = g_task_new (self, NULL, callback, user_data); |
| g_task_set_task_data (task, ctx, (GDestroyNotify)setup_gathering_context_free); |
| |
| g_object_get (self, |
| MM_IFACE_MODEM_LOCATION_DBUS_SKELETON, &ctx->skeleton, |
| MM_IFACE_MODEM_LOCATION_ALLOW_GPS_UNMANAGED_ALWAYS, &allow_gps_unmanaged_always, |
| 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; |
| } |
| |
| /* Get current list of enabled sources */ |
| currently_enabled = mm_gdbus_modem_location_get_enabled (ctx->skeleton); |
| |
| /* Reset the list of sources to enable or disable */ |
| ctx->to_enable = MM_MODEM_LOCATION_SOURCE_NONE; |
| ctx->to_disable = MM_MODEM_LOCATION_SOURCE_NONE; |
| |
| /* Loop through all known bits in the bitmask to enable/disable specific location sources */ |
| for (source = MM_MODEM_LOCATION_SOURCE_FIRST; |
| source <= MM_MODEM_LOCATION_SOURCE_LAST; |
| source = source << 1) { |
| /* skip unsupported sources */ |
| if (!(mm_gdbus_modem_location_get_capabilities (ctx->skeleton) & source)) |
| continue; |
| |
| str = mm_modem_location_source_build_string_from_mask (source); |
| |
| if (mask & source) { |
| /* Source set in mask, need to enable if disabled */ |
| if (currently_enabled & source) |
| mm_obj_dbg (self, "location '%s' gathering is already enabled...", str); |
| else |
| ctx->to_enable |= source; |
| } else { |
| /* Source unset in mask, need to disable if enabled */ |
| if (currently_enabled & source) |
| ctx->to_disable |= source; |
| else |
| mm_obj_dbg (self, "location '%s' gathering is already disabled...", str); |
| } |
| |
| g_free (str); |
| } |
| |
| /* When standard GPS retrieval (RAW/NMEA) is enabled, we cannot enable the |
| * UNMANAGED setup, and viceversa, unless explicitly allowed to do so by the |
| * plugin implementation (e.g. if the RAW/NMEA sources don't use the same TTY |
| * as the GPS UNMANAGED setup. */ |
| if (!allow_gps_unmanaged_always && |
| ((ctx->to_enable & MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED && |
| currently_enabled & (MM_MODEM_LOCATION_SOURCE_GPS_RAW | MM_MODEM_LOCATION_SOURCE_GPS_NMEA)) || |
| (ctx->to_enable & (MM_MODEM_LOCATION_SOURCE_GPS_RAW | MM_MODEM_LOCATION_SOURCE_GPS_NMEA) && |
| currently_enabled & MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED) || |
| (ctx->to_enable & (MM_MODEM_LOCATION_SOURCE_GPS_RAW | MM_MODEM_LOCATION_SOURCE_GPS_NMEA) && |
| ctx->to_enable & MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED))) { |
| g_task_return_new_error (task, |
| MM_CORE_ERROR, |
| MM_CORE_ERROR_FAILED, |
| "Cannot have both unmanaged GPS and raw/nmea GPS enabled at the same time"); |
| g_object_unref (task); |
| return; |
| } |
| |
| /* MSA A-GPS and MSB A-GPS cannot be set at the same time */ |
| if ((ctx->to_enable & MM_MODEM_LOCATION_SOURCE_AGPS_MSA && |
| currently_enabled & MM_MODEM_LOCATION_SOURCE_AGPS_MSB) || |
| (ctx->to_enable & MM_MODEM_LOCATION_SOURCE_AGPS_MSB && |
| currently_enabled & MM_MODEM_LOCATION_SOURCE_AGPS_MSA) || |
| (ctx->to_enable & MM_MODEM_LOCATION_SOURCE_AGPS_MSA && |
| ctx->to_enable & MM_MODEM_LOCATION_SOURCE_AGPS_MSB)) { |
| g_task_return_new_error (task, |
| MM_CORE_ERROR, |
| MM_CORE_ERROR_FAILED, |
| "Cannot have both MSA A-GPS and MSB A-GPS enabled at the same time"); |
| g_object_unref (task); |
| return; |
| } |
| |
| if (ctx->to_enable != MM_MODEM_LOCATION_SOURCE_NONE) { |
| str = mm_modem_location_source_build_string_from_mask (ctx->to_enable); |
| mm_obj_dbg (self, "need to enable the following location sources: '%s'", str); |
| g_free (str); |
| } |
| |
| if (ctx->to_disable != MM_MODEM_LOCATION_SOURCE_NONE) { |
| str = mm_modem_location_source_build_string_from_mask (ctx->to_disable); |
| mm_obj_dbg (self, "need to disable the following location sources: '%s'", str); |
| g_free (str); |
| } |
| |
| /* Start enabling/disabling location sources */ |
| ctx->current = MM_MODEM_LOCATION_SOURCE_FIRST; |
| setup_gathering_step (task); |
| } |
| |
| /*****************************************************************************/ |
| |
| typedef struct { |
| MmGdbusModemLocation *skeleton; |
| GDBusMethodInvocation *invocation; |
| MMIfaceModemLocation *self; |
| guint32 sources; |
| gboolean signal_location; |
| } HandleSetupContext; |
| |
| static void |
| handle_setup_context_free (HandleSetupContext *ctx) |
| { |
| g_object_unref (ctx->skeleton); |
| g_object_unref (ctx->invocation); |
| g_object_unref (ctx->self); |
| g_slice_free (HandleSetupContext, ctx); |
| } |
| |
| static void |
| setup_gathering_ready (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| HandleSetupContext *ctx) |
| { |
| GError *error = NULL; |
| |
| if (!setup_gathering_finish (self, res, &error)) |
| mm_dbus_method_invocation_take_error (ctx->invocation, error); |
| else |
| mm_gdbus_modem_location_complete_setup (ctx->skeleton, ctx->invocation); |
| |
| handle_setup_context_free (ctx); |
| } |
| |
| static void |
| handle_setup_auth_ready (MMIfaceAuth *_self, |
| GAsyncResult *res, |
| HandleSetupContext *ctx) |
| { |
| MMIfaceModemLocation *self = MM_IFACE_MODEM_LOCATION (_self); |
| GError *error = NULL; |
| MMModemState modem_state; |
| MMModemLocationSource not_supported; |
| MMModemLocationSource require_enabled; |
| LocationContext *location_ctx; |
| g_autofree gchar *str = NULL; |
| |
| if (!mm_iface_auth_authorize_finish (_self, res, &error)) { |
| mm_dbus_method_invocation_take_error (ctx->invocation, error); |
| handle_setup_context_free (ctx); |
| return; |
| } |
| |
| /* If any of the location sources being enabled is NOT supported, set error */ |
| not_supported = ((mm_gdbus_modem_location_get_capabilities (ctx->skeleton) ^ ctx->sources) & ctx->sources); |
| if (not_supported != MM_MODEM_LOCATION_SOURCE_NONE) { |
| str = mm_modem_location_source_build_string_from_mask (not_supported); |
| mm_dbus_method_invocation_return_error (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, |
| "Cannot enable unsupported location sources: '%s'", str); |
| handle_setup_context_free (ctx); |
| return; |
| } |
| |
| modem_state = MM_MODEM_STATE_UNKNOWN; |
| g_object_get (self, |
| MM_IFACE_MODEM_STATE, &modem_state, |
| NULL); |
| |
| /* Location sources that require any kind of network access may be |
| * enabled only when the modem is enabled. Generic standalone GPS may be |
| * enabled even without a SIM card */ |
| require_enabled = ctx->sources & (MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI | |
| MM_MODEM_LOCATION_SOURCE_CDMA_BS | |
| MM_MODEM_LOCATION_SOURCE_AGPS_MSA | |
| MM_MODEM_LOCATION_SOURCE_AGPS_MSB); |
| if (require_enabled && (modem_state < MM_MODEM_STATE_ENABLED)) { |
| str = mm_modem_location_source_build_string_from_mask (require_enabled); |
| mm_dbus_method_invocation_return_error (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE, |
| "Cannot enable location '%s': device not yet enabled", str); |
| handle_setup_context_free (ctx); |
| return; |
| } |
| |
| /* Enable/disable location signaling */ |
| location_ctx = get_location_context (ctx->self); |
| if (mm_gdbus_modem_location_get_signals_location (ctx->skeleton) != ctx->signal_location) { |
| mm_obj_dbg (self, "%s location signaling", |
| ctx->signal_location ? "enabling" : "disabling"); |
| mm_gdbus_modem_location_set_signals_location (ctx->skeleton, |
| ctx->signal_location); |
| if (ctx->signal_location) |
| mm_gdbus_modem_location_set_location ( |
| ctx->skeleton, |
| build_location_dictionary (mm_gdbus_modem_location_get_location (ctx->skeleton), |
| location_ctx->location_3gpp, |
| location_ctx->location_gps_nmea, |
| location_ctx->location_gps_raw, |
| location_ctx->location_cdma_bs)); |
| else |
| mm_gdbus_modem_location_set_location ( |
| ctx->skeleton, |
| build_location_dictionary (NULL, NULL, NULL, NULL, NULL)); |
| } |
| |
| str = mm_modem_location_source_build_string_from_mask (ctx->sources); |
| mm_obj_info (self, "processing user request to setup location '%s'...", str); |
| |
| /* Go on to enable or disable the requested sources */ |
| setup_gathering (ctx->self, |
| ctx->sources, |
| (GAsyncReadyCallback)setup_gathering_ready, |
| ctx); |
| } |
| |
| static gboolean |
| handle_setup (MmGdbusModemLocation *skeleton, |
| GDBusMethodInvocation *invocation, |
| guint32 sources, |
| gboolean signal_location, |
| MMIfaceModemLocation *self) |
| { |
| HandleSetupContext *ctx; |
| |
| ctx = g_slice_new0 (HandleSetupContext); |
| ctx->skeleton = g_object_ref (skeleton); |
| ctx->invocation = g_object_ref (invocation); |
| ctx->self = g_object_ref (self); |
| ctx->sources = sources; |
| ctx->signal_location = signal_location; |
| |
| mm_iface_auth_authorize (MM_IFACE_AUTH (self), |
| invocation, |
| MM_AUTHORIZATION_DEVICE_CONTROL, |
| (GAsyncReadyCallback)handle_setup_auth_ready, |
| ctx); |
| return TRUE; |
| } |
| |
| /*****************************************************************************/ |
| |
| typedef struct { |
| MmGdbusModemLocation *skeleton; |
| GDBusMethodInvocation *invocation; |
| MMIfaceModemLocation *self; |
| gchar *supl; |
| } HandleSetSuplServerContext; |
| |
| static void |
| handle_set_supl_server_context_free (HandleSetSuplServerContext *ctx) |
| { |
| g_object_unref (ctx->skeleton); |
| g_object_unref (ctx->invocation); |
| g_object_unref (ctx->self); |
| g_free (ctx->supl); |
| g_slice_free (HandleSetSuplServerContext, ctx); |
| } |
| |
| static void |
| set_supl_server_ready (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| HandleSetSuplServerContext *ctx) |
| { |
| GError *error = NULL; |
| |
| if (!MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->set_supl_server_finish (self, res, &error)) |
| mm_dbus_method_invocation_take_error (ctx->invocation, error); |
| else { |
| mm_gdbus_modem_location_set_supl_server (ctx->skeleton, ctx->supl); |
| mm_gdbus_modem_location_complete_set_supl_server (ctx->skeleton, ctx->invocation); |
| } |
| |
| handle_set_supl_server_context_free (ctx); |
| } |
| |
| static void |
| handle_set_supl_server_auth_ready (MMIfaceAuth *_self, |
| GAsyncResult *res, |
| HandleSetSuplServerContext *ctx) |
| { |
| MMIfaceModemLocation *self = MM_IFACE_MODEM_LOCATION (_self); |
| GError *error = NULL; |
| |
| if (!mm_iface_auth_authorize_finish (_self, res, &error)) { |
| mm_dbus_method_invocation_take_error (ctx->invocation, error); |
| handle_set_supl_server_context_free (ctx); |
| return; |
| } |
| |
| /* If A-GPS is NOT supported, set error */ |
| if (!(mm_gdbus_modem_location_get_capabilities (ctx->skeleton) & (MM_MODEM_LOCATION_SOURCE_AGPS_MSA | MM_MODEM_LOCATION_SOURCE_AGPS_MSB))) { |
| mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, |
| "Cannot set SUPL server: A-GPS not supported"); |
| handle_set_supl_server_context_free (ctx); |
| return; |
| } |
| |
| /* Validate SUPL address string: either FQDN:PORT or IP:PORT */ |
| if (!mm_parse_supl_address (ctx->supl, NULL, NULL, NULL, &error)) { |
| mm_dbus_method_invocation_return_gerror (ctx->invocation, error); |
| handle_set_supl_server_context_free (ctx); |
| return; |
| } |
| |
| /* Check if plugin implements it */ |
| if (!MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->set_supl_server || |
| !MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->set_supl_server_finish) { |
| mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, |
| "Cannot set SUPL server: not implemented"); |
| handle_set_supl_server_context_free (ctx); |
| return; |
| } |
| |
| /* Request to change SUPL server */ |
| mm_obj_info (self, "processing user request to set SUPL server..."); |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->set_supl_server ( |
| ctx->self, |
| ctx->supl, |
| (GAsyncReadyCallback)set_supl_server_ready, |
| ctx); |
| } |
| |
| static gboolean |
| handle_set_supl_server (MmGdbusModemLocation *skeleton, |
| GDBusMethodInvocation *invocation, |
| const gchar *supl, |
| MMIfaceModemLocation *self) |
| { |
| HandleSetSuplServerContext *ctx; |
| |
| ctx = g_slice_new0 (HandleSetSuplServerContext); |
| ctx->skeleton = g_object_ref (skeleton); |
| ctx->invocation = g_object_ref (invocation); |
| ctx->self = g_object_ref (self); |
| ctx->supl = g_strdup (supl); |
| |
| mm_iface_auth_authorize (MM_IFACE_AUTH (self), |
| invocation, |
| MM_AUTHORIZATION_DEVICE_CONTROL, |
| (GAsyncReadyCallback)handle_set_supl_server_auth_ready, |
| ctx); |
| return TRUE; |
| } |
| |
| /*****************************************************************************/ |
| |
| typedef struct { |
| MmGdbusModemLocation *skeleton; |
| GDBusMethodInvocation *invocation; |
| MMIfaceModemLocation *self; |
| GVariant *datav; |
| } HandleInjectAssistanceDataContext; |
| |
| static void |
| handle_inject_assistance_data_context_free (HandleInjectAssistanceDataContext *ctx) |
| { |
| g_object_unref (ctx->skeleton); |
| g_object_unref (ctx->invocation); |
| g_object_unref (ctx->self); |
| g_variant_unref (ctx->datav); |
| g_slice_free (HandleInjectAssistanceDataContext, ctx); |
| } |
| |
| static void |
| inject_assistance_data_ready (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| HandleInjectAssistanceDataContext *ctx) |
| { |
| GError *error = NULL; |
| |
| if (!MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->inject_assistance_data_finish (self, res, &error)) |
| mm_dbus_method_invocation_take_error (ctx->invocation, error); |
| else |
| mm_gdbus_modem_location_complete_inject_assistance_data (ctx->skeleton, ctx->invocation); |
| handle_inject_assistance_data_context_free (ctx); |
| } |
| |
| static void |
| handle_inject_assistance_data_auth_ready (MMIfaceAuth *_self, |
| GAsyncResult *res, |
| HandleInjectAssistanceDataContext *ctx) |
| { |
| MMIfaceModemLocation *self = MM_IFACE_MODEM_LOCATION (_self); |
| GError *error = NULL; |
| const guint8 *data; |
| gsize data_size; |
| |
| if (!mm_iface_auth_authorize_finish (_self, res, &error)) { |
| mm_dbus_method_invocation_take_error (ctx->invocation, error); |
| handle_inject_assistance_data_context_free (ctx); |
| return; |
| } |
| |
| /* If the type is NOT supported, set error */ |
| if (mm_gdbus_modem_location_get_supported_assistance_data (ctx->skeleton) == MM_MODEM_LOCATION_ASSISTANCE_DATA_TYPE_NONE) { |
| mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, |
| "Cannot inject assistance data: ununsupported"); |
| handle_inject_assistance_data_context_free (ctx); |
| return; |
| } |
| |
| /* Check if plugin implements it */ |
| if (!MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->inject_assistance_data || |
| !MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->inject_assistance_data_finish) { |
| mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, |
| "Cannot inject assistance data: not implemented"); |
| handle_inject_assistance_data_context_free (ctx); |
| return; |
| } |
| |
| data = (const guint8 *) g_variant_get_fixed_array (ctx->datav, &data_size, sizeof (guint8)); |
| |
| /* Request to inject assistance data */ |
| mm_obj_info (self, "processing user request to inject assistance data..."); |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->inject_assistance_data ( |
| ctx->self, |
| data, |
| data_size, |
| (GAsyncReadyCallback)inject_assistance_data_ready, |
| ctx); |
| } |
| |
| static gboolean |
| handle_inject_assistance_data (MmGdbusModemLocation *skeleton, |
| GDBusMethodInvocation *invocation, |
| GVariant *datav, |
| MMIfaceModemLocation *self) |
| { |
| HandleInjectAssistanceDataContext *ctx; |
| |
| ctx = g_slice_new0 (HandleInjectAssistanceDataContext); |
| ctx->skeleton = g_object_ref (skeleton); |
| ctx->invocation = g_object_ref (invocation); |
| ctx->self = g_object_ref (self); |
| ctx->datav = g_variant_ref (datav); |
| |
| mm_iface_auth_authorize (MM_IFACE_AUTH (self), |
| invocation, |
| MM_AUTHORIZATION_DEVICE_CONTROL, |
| (GAsyncReadyCallback)handle_inject_assistance_data_auth_ready, |
| ctx); |
| return TRUE; |
| } |
| |
| /*****************************************************************************/ |
| |
| typedef struct { |
| MmGdbusModemLocation *skeleton; |
| GDBusMethodInvocation *invocation; |
| MMIfaceModemLocation *self; |
| guint rate; |
| } HandleSetGpsRefreshRateContext; |
| |
| static void |
| handle_set_gps_refresh_rate_context_free (HandleSetGpsRefreshRateContext *ctx) |
| { |
| g_object_unref (ctx->skeleton); |
| g_object_unref (ctx->invocation); |
| g_object_unref (ctx->self); |
| g_slice_free (HandleSetGpsRefreshRateContext, ctx); |
| } |
| |
| static void |
| handle_set_gps_refresh_rate_auth_ready (MMIfaceAuth *_self, |
| GAsyncResult *res, |
| HandleSetGpsRefreshRateContext *ctx) |
| { |
| MMIfaceModemLocation *self = MM_IFACE_MODEM_LOCATION (_self); |
| GError *error = NULL; |
| |
| if (!mm_iface_auth_authorize_finish (_self, res, &error)) { |
| mm_dbus_method_invocation_take_error (ctx->invocation, error); |
| handle_set_gps_refresh_rate_context_free (ctx); |
| return; |
| } |
| |
| /* If GPS is NOT supported, set error */ |
| if (!(mm_gdbus_modem_location_get_capabilities (ctx->skeleton) & ((MM_MODEM_LOCATION_SOURCE_GPS_RAW | |
| MM_MODEM_LOCATION_SOURCE_GPS_NMEA)))) { |
| mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, |
| "Cannot set GPS refresh rate: GPS not supported"); |
| handle_set_gps_refresh_rate_context_free (ctx); |
| return; |
| } |
| |
| /* Set the new rate in the interface */ |
| mm_obj_info (self, "processing user request to set GPS refresh rate..."); |
| mm_gdbus_modem_location_set_gps_refresh_rate (ctx->skeleton, ctx->rate); |
| mm_gdbus_modem_location_complete_set_gps_refresh_rate (ctx->skeleton, ctx->invocation); |
| handle_set_gps_refresh_rate_context_free (ctx); |
| } |
| |
| static gboolean |
| handle_set_gps_refresh_rate (MmGdbusModemLocation *skeleton, |
| GDBusMethodInvocation *invocation, |
| guint rate, |
| MMIfaceModemLocation *self) |
| { |
| HandleSetGpsRefreshRateContext *ctx; |
| |
| ctx = g_slice_new0 (HandleSetGpsRefreshRateContext); |
| ctx->skeleton = g_object_ref (skeleton); |
| ctx->invocation = g_object_ref (invocation); |
| ctx->self = g_object_ref (self); |
| ctx->rate = rate; |
| |
| mm_iface_auth_authorize (MM_IFACE_AUTH (self), |
| invocation, |
| MM_AUTHORIZATION_DEVICE_CONTROL, |
| (GAsyncReadyCallback)handle_set_gps_refresh_rate_auth_ready, |
| ctx); |
| return TRUE; |
| } |
| |
| /*****************************************************************************/ |
| |
| typedef struct { |
| MmGdbusModemLocation *skeleton; |
| GDBusMethodInvocation *invocation; |
| MMIfaceModemLocation *self; |
| } HandleGetLocationContext; |
| |
| static void |
| handle_get_location_context_free (HandleGetLocationContext *ctx) |
| { |
| g_object_unref (ctx->skeleton); |
| g_object_unref (ctx->invocation); |
| g_object_unref (ctx->self); |
| g_slice_free (HandleGetLocationContext, ctx); |
| } |
| |
| static void |
| handle_get_location_auth_ready (MMIfaceAuth *_self, |
| GAsyncResult *res, |
| HandleGetLocationContext *ctx) |
| { |
| MMIfaceModemLocation *self = MM_IFACE_MODEM_LOCATION (_self); |
| LocationContext *location_ctx; |
| GError *error = NULL; |
| |
| if (!mm_iface_auth_authorize_finish (_self, res, &error)) { |
| mm_dbus_method_invocation_take_error (ctx->invocation, error); |
| handle_get_location_context_free (ctx); |
| return; |
| } |
| |
| mm_obj_info (self, "processing user request to get location..."); |
| location_ctx = get_location_context (ctx->self); |
| mm_gdbus_modem_location_complete_get_location ( |
| ctx->skeleton, |
| ctx->invocation, |
| build_location_dictionary (NULL, |
| location_ctx->location_3gpp, |
| location_ctx->location_gps_nmea, |
| location_ctx->location_gps_raw, |
| location_ctx->location_cdma_bs)); |
| handle_get_location_context_free (ctx); |
| } |
| |
| static gboolean |
| handle_get_location (MmGdbusModemLocation *skeleton, |
| GDBusMethodInvocation *invocation, |
| MMIfaceModemLocation *self) |
| { |
| HandleGetLocationContext *ctx; |
| |
| ctx = g_slice_new0 (HandleGetLocationContext); |
| ctx->skeleton = g_object_ref (skeleton); |
| ctx->invocation = g_object_ref (invocation); |
| ctx->self = g_object_ref (self); |
| |
| mm_iface_auth_authorize (MM_IFACE_AUTH (self), |
| invocation, |
| MM_AUTHORIZATION_LOCATION, |
| (GAsyncReadyCallback)handle_get_location_auth_ready, |
| ctx); |
| return TRUE; |
| } |
| |
| /*****************************************************************************/ |
| |
| typedef struct _DisablingContext DisablingContext; |
| static void interface_disabling_step (GTask *task); |
| |
| typedef enum { |
| DISABLING_STEP_FIRST, |
| DISABLING_STEP_DISABLE_GATHERING, |
| DISABLING_STEP_LAST |
| } DisablingStep; |
| |
| struct _DisablingContext { |
| DisablingStep step; |
| MmGdbusModemLocation *skeleton; |
| }; |
| |
| static void |
| disabling_context_free (DisablingContext *ctx) |
| { |
| if (ctx->skeleton) |
| g_object_unref (ctx->skeleton); |
| g_free (ctx); |
| } |
| |
| gboolean |
| mm_iface_modem_location_disable_finish (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| GError **error) |
| { |
| return g_task_propagate_boolean (G_TASK (res), error); |
| } |
| |
| static void |
| disabling_location_gathering_ready (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| GTask *task) |
| { |
| DisablingContext *ctx; |
| GError *error = NULL; |
| |
| if (!setup_gathering_finish (self, res, &error)) { |
| g_task_return_error (task, error); |
| g_object_unref (task); |
| return; |
| } |
| |
| /* 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) |
| { |
| MMIfaceModemLocation *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_GATHERING: |
| /* We disable all sources here. It is true that the user may have enabled GPS |
| * early before getting the modem enabled, and that we may have left it active |
| * once the modem transitions to enabled state, but for the disabling phase |
| * we reset everything. */ |
| setup_gathering (self, |
| MM_MODEM_LOCATION_SOURCE_NONE, |
| (GAsyncReadyCallback)disabling_location_gathering_ready, |
| task); |
| return; |
| |
| case DISABLING_STEP_LAST: |
| /* We are done without errors! */ |
| clear_location_context (self); |
| g_task_return_boolean (task, TRUE); |
| g_object_unref (task); |
| return; |
| |
| default: |
| break; |
| } |
| |
| g_assert_not_reached (); |
| } |
| |
| void |
| mm_iface_modem_location_disable (MMIfaceModemLocation *self, |
| GAsyncReadyCallback callback, |
| gpointer user_data) |
| { |
| DisablingContext *ctx; |
| GTask *task; |
| |
| ctx = g_new0 (DisablingContext, 1); |
| 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_LOCATION_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_ENABLE_GATHERING, |
| ENABLING_STEP_LAST |
| } EnablingStep; |
| |
| struct _EnablingContext { |
| EnablingStep step; |
| MmGdbusModemLocation *skeleton; |
| }; |
| |
| static void |
| enabling_context_free (EnablingContext *ctx) |
| { |
| if (ctx->skeleton) |
| g_object_unref (ctx->skeleton); |
| g_free (ctx); |
| } |
| |
| gboolean |
| mm_iface_modem_location_enable_finish (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| GError **error) |
| { |
| return g_task_propagate_boolean (G_TASK (res), error); |
| } |
| |
| static void |
| enabling_location_gathering_ready (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| GTask *task) |
| { |
| EnablingContext *ctx; |
| GError *error = NULL; |
| |
| if (!setup_gathering_finish (self, res, &error)) { |
| g_task_return_error (task, error); |
| g_object_unref (task); |
| return; |
| } |
| |
| /* 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) |
| { |
| MMIfaceModemLocation *self; |
| EnablingContext *ctx; |
| |
| /* Don't run new steps if we're cancelled */ |
| if (g_task_return_error_if_cancelled (task)) { |
| g_object_unref (task); |
| return; |
| } |
| |
| 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_ENABLE_GATHERING: { |
| MMModemLocationSource default_sources; |
| MMModemLocationSource currently_enabled; |
| |
| /* By default, we'll enable all NON-GPS sources */ |
| default_sources = mm_gdbus_modem_location_get_capabilities (ctx->skeleton); |
| default_sources &= ~(MM_MODEM_LOCATION_SOURCE_GPS_RAW | |
| MM_MODEM_LOCATION_SOURCE_GPS_NMEA | |
| MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED | |
| MM_MODEM_LOCATION_SOURCE_AGPS_MSA | |
| MM_MODEM_LOCATION_SOURCE_AGPS_MSB); |
| |
| /* If standalone GPS was already enabled, we keep it enabled */ |
| currently_enabled = mm_gdbus_modem_location_get_enabled (ctx->skeleton); |
| |
| setup_gathering (self, |
| default_sources | currently_enabled, |
| (GAsyncReadyCallback)enabling_location_gathering_ready, |
| task); |
| return; |
| } |
| |
| 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_location_enable (MMIfaceModemLocation *self, |
| GCancellable *cancellable, |
| GAsyncReadyCallback callback, |
| gpointer user_data) |
| { |
| EnablingContext *ctx; |
| GTask *task; |
| |
| ctx = g_new0 (EnablingContext, 1); |
| ctx->step = ENABLING_STEP_FIRST; |
| |
| task = g_task_new (self, cancellable, callback, user_data); |
| g_task_set_task_data (task, ctx, (GDestroyNotify)enabling_context_free); |
| |
| g_object_get (self, |
| MM_IFACE_MODEM_LOCATION_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_CAPABILITIES, |
| INITIALIZATION_STEP_VALIDATE_CAPABILITIES, |
| INITIALIZATION_STEP_SUPL_SERVER, |
| INITIALIZATION_STEP_SUPPORTED_ASSISTANCE_DATA, |
| INITIALIZATION_STEP_ASSISTANCE_DATA_SERVERS, |
| INITIALIZATION_STEP_GPS_REFRESH_RATE, |
| INITIALIZATION_STEP_LAST |
| } InitializationStep; |
| |
| struct _InitializationContext { |
| MmGdbusModemLocation *skeleton; |
| InitializationStep step; |
| MMModemLocationSource capabilities; |
| }; |
| |
| static void |
| initialization_context_free (InitializationContext *ctx) |
| { |
| g_object_unref (ctx->skeleton); |
| g_free (ctx); |
| } |
| |
| static void |
| load_assistance_data_servers_ready (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| GTask *task) |
| { |
| GError *error = NULL; |
| InitializationContext *ctx; |
| gchar **servers; |
| |
| ctx = g_task_get_task_data (task); |
| |
| servers = MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_assistance_data_servers_finish (self, res, &error); |
| if (error) { |
| mm_obj_warn (self, "couldn't load assistance data servers: %s", error->message); |
| g_error_free (error); |
| } |
| |
| mm_gdbus_modem_location_set_assistance_data_servers (ctx->skeleton, (const gchar *const *)servers); |
| g_strfreev (servers); |
| |
| /* Go on to next step */ |
| ctx->step++; |
| interface_initialization_step (task); |
| } |
| |
| static void |
| load_supported_assistance_data_ready (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| GTask *task) |
| { |
| GError *error = NULL; |
| MMModemLocationAssistanceDataType mask; |
| InitializationContext *ctx; |
| |
| ctx = g_task_get_task_data (task); |
| |
| mask = MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_supported_assistance_data_finish (self, res, &error); |
| if (error) { |
| mm_obj_warn (self, "couldn't load supported assistance data types: %s", error->message); |
| g_error_free (error); |
| } |
| |
| mm_gdbus_modem_location_set_supported_assistance_data (ctx->skeleton, (guint32) mask); |
| |
| /* Go on to next step */ |
| ctx->step++; |
| interface_initialization_step (task); |
| } |
| |
| static void |
| load_supl_server_ready (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| GTask *task) |
| { |
| GError *error = NULL; |
| gchar *supl; |
| InitializationContext *ctx; |
| |
| ctx = g_task_get_task_data (task); |
| |
| supl = MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_supl_server_finish (self, res, &error); |
| if (error) { |
| mm_obj_warn (self, "couldn't load SUPL server: %s", error->message); |
| g_error_free (error); |
| } |
| |
| mm_gdbus_modem_location_set_supl_server (ctx->skeleton, supl ? supl : ""); |
| g_free (supl); |
| |
| /* Go on to next step */ |
| ctx->step++; |
| interface_initialization_step (task); |
| } |
| |
| static void |
| load_capabilities_ready (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| GTask *task) |
| { |
| GError *error = NULL; |
| InitializationContext *ctx; |
| |
| ctx = g_task_get_task_data (task); |
| |
| ctx->capabilities = MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_capabilities_finish (self, res, &error); |
| if (error) { |
| mm_obj_warn (self, "couldn't load location capabilities: %s", error->message); |
| g_error_free (error); |
| } |
| |
| mm_gdbus_modem_location_set_capabilities (ctx->skeleton, ctx->capabilities); |
| |
| /* Go on to next step */ |
| ctx->step++; |
| interface_initialization_step (task); |
| } |
| |
| static void |
| interface_initialization_step (GTask *task) |
| { |
| MMIfaceModemLocation *self; |
| InitializationContext *ctx; |
| MMModemLocationSource existing_capabilities; |
| |
| /* Don't run new steps if we're cancelled */ |
| if (g_task_return_error_if_cancelled (task)) { |
| g_object_unref (task); |
| return; |
| } |
| |
| self = g_task_get_source_object (task); |
| ctx = g_task_get_task_data (task); |
| |
| switch (ctx->step) { |
| case INITIALIZATION_STEP_FIRST: |
| ctx->step++; |
| /* fall through */ |
| |
| case INITIALIZATION_STEP_CAPABILITIES: |
| /* Location capabilities value is meant to be loaded only once during |
| * the whole lifetime of the modem. Therefore, if we already have it |
| * loaded, don't try to load it again. */ |
| existing_capabilities = mm_gdbus_modem_location_get_capabilities (ctx->skeleton); |
| if (existing_capabilities != MM_MODEM_LOCATION_SOURCE_NONE) { |
| ctx->capabilities = existing_capabilities; |
| } else if (MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_capabilities && |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_capabilities_finish) { |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_capabilities ( |
| self, |
| (GAsyncReadyCallback)load_capabilities_ready, |
| task); |
| return; |
| } |
| ctx->step++; |
| /* fall through */ |
| |
| case INITIALIZATION_STEP_VALIDATE_CAPABILITIES: |
| /* If the modem doesn't support any location capabilities, we won't export |
| * the interface. We just report an UNSUPPORTED error. */ |
| if (ctx->capabilities == MM_MODEM_LOCATION_SOURCE_NONE) { |
| g_task_return_new_error (task, |
| MM_CORE_ERROR, |
| MM_CORE_ERROR_UNSUPPORTED, |
| "The modem doesn't have location capabilities"); |
| g_object_unref (task); |
| return; |
| } |
| ctx->step++; |
| /* fall through */ |
| |
| case INITIALIZATION_STEP_SUPL_SERVER: |
| /* If the modem supports A-GPS, load SUPL server */ |
| if ((ctx->capabilities & (MM_MODEM_LOCATION_SOURCE_AGPS_MSA | |
| MM_MODEM_LOCATION_SOURCE_AGPS_MSB)) && |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_supl_server && |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_supl_server_finish) { |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_supl_server ( |
| self, |
| (GAsyncReadyCallback)load_supl_server_ready, |
| task); |
| return; |
| } |
| ctx->step++; |
| /* fall through */ |
| |
| case INITIALIZATION_STEP_SUPPORTED_ASSISTANCE_DATA: |
| /* If the modem supports any GPS-related technology, check assistance data types supported */ |
| if ((ctx->capabilities & (MM_MODEM_LOCATION_SOURCE_AGPS_MSA | |
| MM_MODEM_LOCATION_SOURCE_AGPS_MSB | |
| MM_MODEM_LOCATION_SOURCE_GPS_RAW | |
| MM_MODEM_LOCATION_SOURCE_GPS_NMEA)) && |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_supported_assistance_data && |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_supported_assistance_data_finish) { |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_supported_assistance_data ( |
| self, |
| (GAsyncReadyCallback)load_supported_assistance_data_ready, |
| task); |
| return; |
| } |
| ctx->step++; |
| /* fall through */ |
| |
| case INITIALIZATION_STEP_ASSISTANCE_DATA_SERVERS: |
| /* If any assistance data supported, load servers */ |
| if ((mm_gdbus_modem_location_get_supported_assistance_data (ctx->skeleton) != MM_MODEM_LOCATION_ASSISTANCE_DATA_TYPE_NONE) && |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_assistance_data_servers && |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_assistance_data_servers_finish) { |
| MM_IFACE_MODEM_LOCATION_GET_IFACE (self)->load_assistance_data_servers ( |
| self, |
| (GAsyncReadyCallback)load_assistance_data_servers_ready, |
| task); |
| return; |
| } |
| ctx->step++; |
| /* fall through */ |
| |
| case INITIALIZATION_STEP_GPS_REFRESH_RATE: |
| /* If we have GPS capabilities, expose the GPS refresh rate */ |
| if (ctx->capabilities & ((MM_MODEM_LOCATION_SOURCE_GPS_RAW | |
| MM_MODEM_LOCATION_SOURCE_GPS_NMEA))) |
| /* Set the default rate in the interface */ |
| mm_gdbus_modem_location_set_gps_refresh_rate (ctx->skeleton, MM_LOCATION_GPS_REFRESH_TIME_SECS); |
| |
| ctx->step++; |
| /* fall through */ |
| |
| case INITIALIZATION_STEP_LAST: |
| /* We are done without errors! */ |
| |
| /* Handle method invocations */ |
| g_signal_connect (ctx->skeleton, |
| "handle-setup", |
| G_CALLBACK (handle_setup), |
| self); |
| g_signal_connect (ctx->skeleton, |
| "handle-set-supl-server", |
| G_CALLBACK (handle_set_supl_server), |
| self); |
| g_signal_connect (ctx->skeleton, |
| "handle-inject-assistance-data", |
| G_CALLBACK (handle_inject_assistance_data), |
| self); |
| g_signal_connect (ctx->skeleton, |
| "handle-set-gps-refresh-rate", |
| G_CALLBACK (handle_set_gps_refresh_rate), |
| self); |
| g_signal_connect (ctx->skeleton, |
| "handle-get-location", |
| G_CALLBACK (handle_get_location), |
| self); |
| |
| /* Finally, export the new interface */ |
| mm_gdbus_object_skeleton_set_modem_location (MM_GDBUS_OBJECT_SKELETON (self), |
| MM_GDBUS_MODEM_LOCATION (ctx->skeleton)); |
| |
| g_task_return_boolean (task, TRUE); |
| g_object_unref (task); |
| return; |
| |
| default: |
| break; |
| } |
| |
| g_assert_not_reached (); |
| } |
| |
| gboolean |
| mm_iface_modem_location_initialize_finish (MMIfaceModemLocation *self, |
| GAsyncResult *res, |
| GError **error) |
| { |
| return g_task_propagate_boolean (G_TASK (res), error); |
| } |
| |
| void |
| mm_iface_modem_location_initialize (MMIfaceModemLocation *self, |
| GCancellable *cancellable, |
| GAsyncReadyCallback callback, |
| gpointer user_data) |
| { |
| InitializationContext *ctx; |
| MmGdbusModemLocation *skeleton = NULL; |
| GTask *task; |
| |
| /* Did we already create it? */ |
| g_object_get (self, |
| MM_IFACE_MODEM_LOCATION_DBUS_SKELETON, &skeleton, |
| NULL); |
| if (!skeleton) { |
| skeleton = mm_gdbus_modem_location_skeleton_new (); |
| |
| /* Set all initial property defaults */ |
| mm_gdbus_modem_location_set_capabilities (skeleton, MM_MODEM_LOCATION_SOURCE_NONE); |
| mm_gdbus_modem_location_set_supported_assistance_data (skeleton, MM_MODEM_LOCATION_ASSISTANCE_DATA_TYPE_NONE); |
| mm_gdbus_modem_location_set_enabled (skeleton, MM_MODEM_LOCATION_SOURCE_NONE); |
| mm_gdbus_modem_location_set_signals_location (skeleton, FALSE); |
| mm_gdbus_modem_location_set_location (skeleton, |
| build_location_dictionary (NULL, NULL, NULL, NULL, NULL)); |
| |
| g_object_set (self, |
| MM_IFACE_MODEM_LOCATION_DBUS_SKELETON, skeleton, |
| NULL); |
| } |
| |
| /* Perform async initialization here */ |
| |
| ctx = g_new0 (InitializationContext, 1); |
| ctx->capabilities = MM_MODEM_LOCATION_SOURCE_NONE; |
| ctx->step = INITIALIZATION_STEP_FIRST; |
| ctx->skeleton = skeleton; |
| |
| task = g_task_new (self, cancellable, callback, user_data); |
| g_task_set_task_data (task, ctx, (GDestroyNotify)initialization_context_free); |
| |
| interface_initialization_step (task); |
| } |
| |
| void |
| mm_iface_modem_location_shutdown (MMIfaceModemLocation *self) |
| { |
| /* Unexport DBus interface and remove the skeleton */ |
| mm_gdbus_object_skeleton_set_modem_location (MM_GDBUS_OBJECT_SKELETON (self), NULL); |
| g_object_set (self, |
| MM_IFACE_MODEM_LOCATION_DBUS_SKELETON, NULL, |
| NULL); |
| } |
| |
| /*****************************************************************************/ |
| |
| static void |
| mm_iface_modem_location_default_init (MMIfaceModemLocationInterface *iface) |
| { |
| static gsize initialized = 0; |
| |
| if (!g_once_init_enter (&initialized)) |
| return; |
| |
| /* Properties */ |
| g_object_interface_install_property ( |
| iface, |
| g_param_spec_object (MM_IFACE_MODEM_LOCATION_DBUS_SKELETON, |
| "Location DBus skeleton", |
| "DBus skeleton for the Location interface", |
| MM_GDBUS_TYPE_MODEM_LOCATION_SKELETON, |
| G_PARAM_READWRITE)); |
| |
| g_object_interface_install_property ( |
| iface, |
| g_param_spec_boolean (MM_IFACE_MODEM_LOCATION_ALLOW_GPS_UNMANAGED_ALWAYS, |
| "Allow unmanaged GPS always", |
| "Whether to always allow GPS unmanaged, even when raw/nmea GPS sources are enabled", |
| FALSE, |
| G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); |
| |
| g_once_init_leave (&initialized, 1); |
| } |