The panel supports 2G/3G/4G GSM/LTE modems. CDMA2000 Modems are not supported. If a supported modem is present, the panel will be shown and the modem will be handled, else, network-panel shall manage the modem as it did in the past. If more than one modem with data enabled is present, the user is allowed to set priority of one SIM over the other (the priority is for SIM, not modem). Fixes https://gitlab.gnome.org/GNOME/gnome-control-center/issues/132
1446 lines
40 KiB
C
1446 lines
40 KiB
C
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||
/* cc-wwan-data.c
|
||
*
|
||
* Copyright 2019 Purism SPC
|
||
*
|
||
* 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 3 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
*
|
||
* Author(s):
|
||
* Mohammed Sadiq <sadiq@sadiqpk.org>
|
||
*
|
||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||
*/
|
||
|
||
#undef G_LOG_DOMAIN
|
||
#define G_LOG_DOMAIN "cc-wwan-data"
|
||
|
||
#ifdef HAVE_CONFIG_H
|
||
# include <config.h>
|
||
#endif
|
||
|
||
#define _GNU_SOURCE
|
||
#include <string.h>
|
||
#include <glib/gi18n.h>
|
||
#include <nma-mobile-providers.h>
|
||
|
||
#include "cc-wwan-data.h"
|
||
|
||
/**
|
||
* @short_description: Device Internet Data Object
|
||
* @include: "cc-wwan-device-data.h"
|
||
*
|
||
* #CcWwanData represents the data object of the given
|
||
* #CcWwanDevice. Please note that while #CcWWanDevice
|
||
* is bound to the hardware device, #CcWwanData may also
|
||
* depend on the inserted SIM (if supported). So the state
|
||
* of #CcWwanData changes when SIM is changed.
|
||
*/
|
||
|
||
/* Priority for connections. larger the number, lower the priority */
|
||
#define CC_WWAN_DNS_PRIORITY_LOW (20)
|
||
#define CC_WWAN_DNS_PRIORITY_HIGH (15)
|
||
|
||
/* These are to be set as route metric */
|
||
#define CC_WWAN_ROUTE_PRIORITY_LOW (1050)
|
||
#define CC_WWAN_ROUTE_PRIORITY_HIGH (1040)
|
||
|
||
struct _CcWwanData
|
||
{
|
||
GObject parent_instance;
|
||
|
||
MMObject *mm_object;
|
||
MMModem *modem;
|
||
MMSim *sim;
|
||
gchar *sim_id;
|
||
|
||
gchar *operator_code; /* MCCMNC */
|
||
GError *error;
|
||
|
||
NMClient *nm_client;
|
||
NMDevice *nm_device;
|
||
NMAMobileProvidersDatabase *apn_db;
|
||
NMAMobileProvider *apn_provider;
|
||
CcWwanDataApn *default_apn;
|
||
CcWwanDataApn *old_default_apn;
|
||
GListStore *apn_list;
|
||
NMActiveConnection *active_connection;
|
||
|
||
gint priority;
|
||
gboolean data_enabled; /* autoconnect enabled */
|
||
gboolean home_only; /* Data roaming */
|
||
};
|
||
|
||
G_DEFINE_TYPE (CcWwanData, cc_wwan_data, G_TYPE_OBJECT)
|
||
|
||
/*
|
||
* Default Access Point Settings Logic:
|
||
* For a provided SIM, all the APNs available from NetworkManager
|
||
* that matches the given SIM identifier (ICCID, available via
|
||
* mm_sim_get_identifier() or similar gdbus API) is loaded for
|
||
* the Device (In NetworkManager, it is saved as ‘sim-id’, if
|
||
* present). At a time, only one connection will be bound to
|
||
* a device. If there are more than one match, the item with
|
||
* the highest ‘route-metric’ is taken. If more matches are
|
||
* still available, the first item is chosen.
|
||
*
|
||
* Populating All available APNs:
|
||
* All Possible APNs for the given sim are populated the following
|
||
* way (A list of all the following avoiding duplicates)
|
||
* 1. The above mentioned “Default Access Point Settings Logic”
|
||
* 2. Get All saved Network Manager connections with the
|
||
* provided MCCMNC of the given SIM
|
||
* 3. Get All possible APNs for the MCCMNC from mobile-provider-info
|
||
*
|
||
* Testing if data is enabled:
|
||
* Check if any of the items from step 1 have ‘autoconnect’ set
|
||
*
|
||
* Checking/Setting current SIM for data (in case of multiple SIM):
|
||
* Since other networks (like wifi, ethernet) should have higher
|
||
* priorities we use a negative number for priority.
|
||
* 1. All APNs by default have priority CC_WWAN_APN_PRIORITY_LOW
|
||
* 2. APN of selected SIM for active data have priority of
|
||
* CC_WWAN_APN_PRIORITY_HIGH
|
||
*
|
||
* XXX: Since users may create custom APNs via nmtui or like tools
|
||
* we may have to check if there are some inconsistencies with APNs
|
||
* available in NetworkManager, and ask user if they have to reset
|
||
* the APNs that have invalid settings (basically, we care only APNs
|
||
* that are set to have ‘autoconnect’ enabled, and all we need is to
|
||
* disable autoconnect). We won’t interfere CDMA/EVDO networks.
|
||
*/
|
||
struct _CcWwanDataApn {
|
||
GObject parent_instance;
|
||
|
||
/* Set if the APN is from the mobile-provider-info database */
|
||
NMAMobileAccessMethod *access_method;
|
||
|
||
/* Set if the APN is saved in NetworkManager */
|
||
NMConnection *nm_connection;
|
||
NMRemoteConnection *remote_connection;
|
||
|
||
gboolean modified;
|
||
};
|
||
|
||
G_DEFINE_TYPE (CcWwanDataApn, cc_wwan_data_apn, G_TYPE_OBJECT)
|
||
|
||
enum {
|
||
PROP_0,
|
||
PROP_ERROR,
|
||
PROP_ENABLED,
|
||
N_PROPS
|
||
};
|
||
|
||
static GParamSpec *properties[N_PROPS];
|
||
|
||
static void
|
||
wwan_data_apn_reset (CcWwanDataApn *apn)
|
||
{
|
||
if (!apn)
|
||
return;
|
||
|
||
g_clear_object (&apn->nm_connection);
|
||
g_clear_object (&apn->remote_connection);
|
||
}
|
||
|
||
static NMConnection *
|
||
wwan_data_get_nm_connection (CcWwanDataApn *apn)
|
||
{
|
||
NMConnection *connection;
|
||
NMSetting *setting;
|
||
g_autofree gchar *uuid = NULL;
|
||
|
||
if (apn->nm_connection)
|
||
return apn->nm_connection;
|
||
|
||
if (apn->remote_connection)
|
||
return NM_CONNECTION (apn->remote_connection);
|
||
|
||
connection = nm_simple_connection_new ();
|
||
apn->nm_connection = connection;
|
||
|
||
setting = nm_setting_connection_new ();
|
||
uuid = nm_utils_uuid_generate ();
|
||
g_object_set (setting,
|
||
NM_SETTING_CONNECTION_UUID, uuid,
|
||
NM_SETTING_CONNECTION_TYPE, NM_SETTING_GSM_SETTING_NAME,
|
||
NULL);
|
||
nm_connection_add_setting (connection, setting);
|
||
|
||
setting = nm_setting_serial_new ();
|
||
nm_connection_add_setting (connection, setting);
|
||
|
||
setting = nm_setting_ip4_config_new ();
|
||
g_object_set (setting, NM_SETTING_IP_CONFIG_METHOD, "auto", NULL);
|
||
nm_connection_add_setting (connection, setting);
|
||
|
||
nm_connection_add_setting (connection, nm_setting_gsm_new ());
|
||
nm_connection_add_setting (connection, nm_setting_ppp_new ());
|
||
|
||
return apn->nm_connection;
|
||
}
|
||
|
||
static gboolean
|
||
wwan_data_apn_are_same (NMRemoteConnection *remote_connection,
|
||
NMAMobileAccessMethod *access_method)
|
||
{
|
||
NMConnection *connection;
|
||
NMSetting *setting;
|
||
|
||
if (!remote_connection)
|
||
return FALSE;
|
||
|
||
connection = NM_CONNECTION (remote_connection);
|
||
setting = NM_SETTING (nm_connection_get_setting_gsm (connection));
|
||
|
||
if (g_strcmp0 (nma_mobile_access_method_get_3gpp_apn (access_method),
|
||
nm_setting_gsm_get_apn (NM_SETTING_GSM (setting))) != 0)
|
||
return FALSE;
|
||
|
||
if (g_strcmp0 (nma_mobile_access_method_get_username (access_method),
|
||
nm_setting_gsm_get_username (NM_SETTING_GSM (setting))) != 0)
|
||
return FALSE;
|
||
|
||
if (g_strcmp0 (nma_mobile_access_method_get_password (access_method),
|
||
nm_setting_gsm_get_password (NM_SETTING_GSM (setting))) != 0)
|
||
return FALSE;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static CcWwanDataApn *
|
||
wwan_data_find_matching_apn (CcWwanData *self,
|
||
NMAMobileAccessMethod *access_method)
|
||
{
|
||
CcWwanDataApn *apn;
|
||
guint i, n_items;
|
||
|
||
n_items = g_list_model_get_n_items (G_LIST_MODEL (self->apn_list));
|
||
|
||
for (i = 0; i < n_items; i++)
|
||
{
|
||
apn = g_list_model_get_item (G_LIST_MODEL (self->apn_list), i);
|
||
|
||
if (apn->access_method == access_method)
|
||
return apn;
|
||
|
||
if (wwan_data_apn_are_same (apn->remote_connection,
|
||
access_method))
|
||
return apn;
|
||
|
||
g_object_unref (apn);
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
static gboolean
|
||
wwan_data_nma_method_is_mms (NMAMobileAccessMethod *method)
|
||
{
|
||
const char *str;
|
||
|
||
str = nma_mobile_access_method_get_3gpp_apn (method);
|
||
if (str && strcasestr (str, "mms"))
|
||
return TRUE;
|
||
|
||
str = nma_mobile_access_method_get_name (method);
|
||
if (str && strcasestr (str, "mms"))
|
||
return TRUE;
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
static void
|
||
wwan_data_update_apn_list_db (CcWwanData *self)
|
||
{
|
||
GSList *apn_methods = NULL, *l;
|
||
g_autoptr(GError) error = NULL;
|
||
guint i = 0;
|
||
|
||
if (!self->sim || !self->operator_code)
|
||
return;
|
||
|
||
if (!self->apn_list)
|
||
self->apn_list = g_list_store_new (CC_TYPE_WWAN_DATA_APN);
|
||
|
||
if (!self->apn_db)
|
||
self->apn_db = nma_mobile_providers_database_new_sync (NULL, NULL, NULL, &error);
|
||
|
||
if (error)
|
||
{
|
||
g_warning ("%s", error->message);
|
||
return;
|
||
}
|
||
|
||
if (!self->apn_provider)
|
||
self->apn_provider = nma_mobile_providers_database_lookup_3gpp_mcc_mnc (self->apn_db,
|
||
self->operator_code);
|
||
|
||
if (self->apn_provider)
|
||
apn_methods = nma_mobile_provider_get_methods (self->apn_provider);
|
||
|
||
for (l = apn_methods; l; l = l->next, i++)
|
||
{
|
||
g_autoptr(CcWwanDataApn) apn = NULL;
|
||
|
||
/* We don’t list MMS APNs */
|
||
if (wwan_data_nma_method_is_mms (l->data))
|
||
continue;
|
||
|
||
apn = wwan_data_find_matching_apn (self, l->data);
|
||
|
||
/* Prepend the item in order */
|
||
if (!apn)
|
||
{
|
||
apn = cc_wwan_data_apn_new ();
|
||
g_list_store_insert (self->apn_list, i, apn);
|
||
}
|
||
|
||
apn->access_method = l->data;
|
||
}
|
||
}
|
||
|
||
static void
|
||
wwan_data_update_apn_list (CcWwanData *self)
|
||
{
|
||
const GPtrArray *nm_connections;
|
||
guint i;
|
||
|
||
if (self->apn_list || !self->sim)
|
||
return;
|
||
|
||
if (!self->apn_list)
|
||
self->apn_list = g_list_store_new (CC_TYPE_WWAN_DATA_APN);
|
||
|
||
if (self->nm_device)
|
||
{
|
||
nm_connections = nm_device_get_available_connections (self->nm_device);
|
||
|
||
for (i = 0; i < nm_connections->len; i++)
|
||
{
|
||
g_autoptr(CcWwanDataApn) apn = NULL;
|
||
|
||
apn = cc_wwan_data_apn_new ();
|
||
apn->remote_connection = g_object_ref (nm_connections->pdata[i]);
|
||
g_list_store_append (self->apn_list, apn);
|
||
|
||
/* Load the default APN */
|
||
if (!self->default_apn && self->sim_id)
|
||
{
|
||
NMSettingConnection *connection_setting;
|
||
NMSettingIPConfig *ip_setting;
|
||
NMSettingGsm *setting;
|
||
NMConnection *connection;
|
||
const gchar *sim_id;
|
||
|
||
connection = NM_CONNECTION (apn->remote_connection);
|
||
setting = nm_connection_get_setting_gsm (connection);
|
||
connection_setting = nm_connection_get_setting_connection (connection);
|
||
sim_id = nm_setting_gsm_get_sim_id (setting);
|
||
|
||
if (sim_id && *sim_id && g_str_equal (sim_id, self->sim_id))
|
||
{
|
||
self->default_apn = apn;
|
||
self->home_only = nm_setting_gsm_get_home_only (setting);
|
||
self->data_enabled = nm_setting_connection_get_autoconnect (connection_setting);
|
||
|
||
/* If any of the APN has a high priority, the device have high priority */
|
||
ip_setting = nm_connection_get_setting_ip4_config (connection);
|
||
if (nm_setting_ip_config_get_route_metric (ip_setting) == CC_WWAN_ROUTE_PRIORITY_HIGH)
|
||
self->priority = CC_WWAN_APN_PRIORITY_HIGH;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
static void
|
||
wwan_device_state_changed_cb (CcWwanData *self)
|
||
{
|
||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ENABLED]);
|
||
}
|
||
|
||
static void
|
||
cc_wwan_data_get_property (GObject *object,
|
||
guint prop_id,
|
||
GValue *value,
|
||
GParamSpec *pspec)
|
||
{
|
||
CcWwanData *self = (CcWwanData *)object;
|
||
|
||
switch (prop_id)
|
||
{
|
||
case PROP_ERROR:
|
||
g_value_set_boolean (value, self->error != NULL);
|
||
break;
|
||
|
||
case PROP_ENABLED:
|
||
g_value_set_boolean (value, cc_wwan_data_get_enabled (self));
|
||
break;
|
||
|
||
default:
|
||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||
}
|
||
}
|
||
|
||
static void
|
||
cc_wwan_data_dispose (GObject *object)
|
||
{
|
||
CcWwanData *self = (CcWwanData *)object;
|
||
|
||
g_clear_pointer (&self->sim_id, g_free);
|
||
g_clear_pointer (&self->operator_code, g_free);
|
||
g_clear_error (&self->error);
|
||
g_clear_object (&self->apn_list);
|
||
g_clear_object (&self->modem);
|
||
g_clear_object (&self->mm_object);
|
||
g_clear_object (&self->nm_client);
|
||
g_clear_object (&self->active_connection);
|
||
g_clear_object (&self->apn_db);
|
||
|
||
G_OBJECT_CLASS (cc_wwan_data_parent_class)->dispose (object);
|
||
}
|
||
|
||
static void
|
||
cc_wwan_data_class_init (CcWwanDataClass *klass)
|
||
{
|
||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
|
||
object_class->get_property = cc_wwan_data_get_property;
|
||
object_class->dispose = cc_wwan_data_dispose;
|
||
|
||
properties[PROP_ERROR] =
|
||
g_param_spec_boolean ("error",
|
||
"Error",
|
||
"Set if some Error occurs",
|
||
FALSE,
|
||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||
|
||
properties[PROP_ENABLED] =
|
||
g_param_spec_boolean ("enabled",
|
||
"Enabled",
|
||
"Get if the data is enabled",
|
||
FALSE,
|
||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||
|
||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||
}
|
||
|
||
static void
|
||
cc_wwan_data_init (CcWwanData *self)
|
||
{
|
||
self->home_only = TRUE;
|
||
self->priority = CC_WWAN_APN_PRIORITY_LOW;
|
||
}
|
||
|
||
/**
|
||
* cc_wwan_data_new:
|
||
* @mm_object: An #MMObject
|
||
* @nm_client: An #NMClient
|
||
*
|
||
* Create a new device data representing the given
|
||
* @mm_object. If @mm_object isn’t a 3G/CDMA/LTE
|
||
* modem, %NULL will be returned
|
||
*
|
||
* Returns: A #CcWwanData or %NULL.
|
||
*/
|
||
CcWwanData *
|
||
cc_wwan_data_new (MMObject *mm_object,
|
||
NMClient *nm_client)
|
||
{
|
||
CcWwanData *self;
|
||
NMDevice *nm_device = NULL;
|
||
g_autoptr(MMModem) modem = NULL;
|
||
NMDeviceModemCapabilities capabilities = 0;
|
||
|
||
g_return_val_if_fail (MM_IS_OBJECT (mm_object), NULL);
|
||
g_return_val_if_fail (NM_CLIENT (nm_client), NULL);
|
||
|
||
modem = mm_object_get_modem (mm_object);
|
||
|
||
if (modem)
|
||
nm_device = nm_client_get_device_by_iface (nm_client,
|
||
mm_modem_get_primary_port (modem));
|
||
|
||
if (NM_IS_DEVICE_MODEM (nm_device))
|
||
capabilities = nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (nm_device));
|
||
|
||
if (!(capabilities & (NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS
|
||
| NM_DEVICE_MODEM_CAPABILITY_LTE)))
|
||
return NULL;
|
||
|
||
self = g_object_new (CC_TYPE_WWAN_DATA, NULL);
|
||
|
||
self->nm_client = g_object_ref (nm_client);
|
||
self->mm_object = g_object_ref (mm_object);
|
||
self->modem = g_steal_pointer (&modem);
|
||
self->sim = mm_modem_get_sim_sync (self->modem, NULL, NULL);
|
||
self->sim_id = mm_sim_dup_identifier (self->sim);
|
||
self->operator_code = mm_sim_dup_operator_identifier (self->sim);
|
||
self->nm_device = g_object_ref (nm_device);
|
||
self->active_connection = nm_device_get_active_connection (nm_device);
|
||
|
||
if (!self->operator_code)
|
||
{
|
||
MMModem3gpp *modem_3gpp;
|
||
|
||
modem_3gpp = mm_object_peek_modem_3gpp (mm_object);
|
||
if (modem_3gpp)
|
||
self->operator_code = mm_modem_3gpp_dup_operator_code (modem_3gpp);
|
||
}
|
||
|
||
if (self->active_connection)
|
||
g_object_ref (self->active_connection);
|
||
|
||
g_signal_connect_object (self->nm_device, "notify::state",
|
||
G_CALLBACK (wwan_device_state_changed_cb),
|
||
self, G_CONNECT_SWAPPED);
|
||
|
||
wwan_data_update_apn_list (self);
|
||
wwan_data_update_apn_list_db (self);
|
||
|
||
return self;
|
||
}
|
||
|
||
GError *
|
||
cc_wwan_data_get_error (CcWwanData *self)
|
||
{
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL);
|
||
|
||
return self->error;
|
||
}
|
||
|
||
const gchar *
|
||
cc_wwan_data_get_simple_html_error (CcWwanData *self)
|
||
{
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL);
|
||
|
||
if (!self->error)
|
||
return NULL;
|
||
|
||
if (g_error_matches (self->error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||
return _("Operation Cancelled");
|
||
|
||
if (g_error_matches (self->error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED))
|
||
return _("<b>Error:</b> Access denied changing settings");
|
||
|
||
if (self->error->domain == MM_MOBILE_EQUIPMENT_ERROR)
|
||
return _("<b>Error:</b> Mobile Equipment Error");
|
||
|
||
return NULL;
|
||
}
|
||
|
||
GListModel *
|
||
cc_wwan_data_get_apn_list (CcWwanData *self)
|
||
{
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL);
|
||
|
||
if (!self->apn_list)
|
||
wwan_data_update_apn_list (self);
|
||
|
||
return G_LIST_MODEL (self->apn_list);
|
||
}
|
||
|
||
static gboolean
|
||
wwan_data_apn_is_new (CcWwanDataApn *apn)
|
||
{
|
||
return apn->remote_connection == NULL;
|
||
}
|
||
|
||
static void
|
||
wwan_data_update_apn (CcWwanData *self,
|
||
CcWwanDataApn *apn,
|
||
NMConnection *connection)
|
||
{
|
||
NMSetting *setting;
|
||
const gchar *name, *username, *password, *apn_name;
|
||
gint dns_priority, route_metric;
|
||
|
||
setting = NM_SETTING (nm_connection_get_setting_connection (connection));
|
||
|
||
g_object_set (setting,
|
||
NM_SETTING_CONNECTION_AUTOCONNECT, self->data_enabled,
|
||
NULL);
|
||
|
||
setting = NM_SETTING (nm_connection_get_setting_gsm (connection));
|
||
|
||
g_object_set (setting,
|
||
NM_SETTING_GSM_HOME_ONLY, self->home_only,
|
||
NULL);
|
||
|
||
setting = NM_SETTING (nm_connection_get_setting_ip4_config (connection));
|
||
if (self->priority == CC_WWAN_APN_PRIORITY_HIGH &&
|
||
self->default_apn == apn)
|
||
{
|
||
dns_priority = CC_WWAN_DNS_PRIORITY_HIGH;
|
||
route_metric = CC_WWAN_ROUTE_PRIORITY_HIGH;
|
||
}
|
||
else
|
||
{
|
||
dns_priority = CC_WWAN_DNS_PRIORITY_LOW;
|
||
route_metric = CC_WWAN_ROUTE_PRIORITY_LOW;
|
||
}
|
||
|
||
g_object_set (setting,
|
||
NM_SETTING_IP_CONFIG_DNS_PRIORITY, dns_priority,
|
||
NM_SETTING_IP_CONFIG_ROUTE_METRIC, (gint64)route_metric,
|
||
NULL);
|
||
|
||
if (apn->access_method && !apn->remote_connection)
|
||
{
|
||
name = nma_mobile_access_method_get_name (apn->access_method);
|
||
username = nma_mobile_access_method_get_username (apn->access_method);
|
||
password = nma_mobile_access_method_get_password (apn->access_method);
|
||
apn_name = nma_mobile_access_method_get_3gpp_apn (apn->access_method);
|
||
}
|
||
else
|
||
{
|
||
return;
|
||
}
|
||
|
||
setting = NM_SETTING (nm_connection_get_setting_gsm (connection));
|
||
g_object_set (setting,
|
||
NM_SETTING_GSM_USERNAME, username,
|
||
NM_SETTING_GSM_PASSWORD, password,
|
||
NM_SETTING_GSM_APN, apn_name,
|
||
NULL);
|
||
|
||
setting = NM_SETTING (nm_connection_get_setting_connection (connection));
|
||
|
||
g_object_set (setting,
|
||
NM_SETTING_CONNECTION_ID, name,
|
||
NULL);
|
||
}
|
||
|
||
static gint
|
||
wwan_data_get_apn_index (CcWwanData *self,
|
||
CcWwanDataApn *apn)
|
||
{
|
||
GListModel *model;
|
||
guint i, n_items;
|
||
|
||
model = G_LIST_MODEL (self->apn_list);
|
||
n_items = g_list_model_get_n_items (model);
|
||
|
||
for (i = 0; i < n_items; i++)
|
||
{
|
||
g_autoptr(CcWwanDataApn) cached_apn = NULL;
|
||
|
||
cached_apn = g_list_model_get_item (model, i);
|
||
|
||
if (apn == cached_apn)
|
||
return i;
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
static void
|
||
cc_wwan_data_connection_updated_cb (GObject *object,
|
||
GAsyncResult *result,
|
||
gpointer user_data)
|
||
{
|
||
CcWwanData *self;
|
||
CcWwanDataApn *apn;
|
||
g_autoptr(GTask) task = user_data;
|
||
g_autoptr(GError) error = NULL;
|
||
|
||
self = g_task_get_source_object (G_TASK (task));
|
||
apn = g_task_get_task_data (G_TASK (task));
|
||
|
||
nm_remote_connection_commit_changes_finish (apn->remote_connection,
|
||
result, &error);
|
||
if (!error)
|
||
{
|
||
guint apn_index;
|
||
apn_index = wwan_data_get_apn_index (self, apn);
|
||
|
||
if (apn_index >= 0)
|
||
g_list_model_items_changed (G_LIST_MODEL (self->apn_list),
|
||
apn_index, 1, 1);
|
||
else
|
||
g_warning ("APN ‘%s’ not in APN list",
|
||
cc_wwan_data_apn_get_name (apn));
|
||
|
||
apn->modified = FALSE;
|
||
g_task_return_boolean (task, TRUE);
|
||
}
|
||
else
|
||
{
|
||
g_task_return_error (task, g_steal_pointer (&error));
|
||
}
|
||
}
|
||
|
||
static void
|
||
cc_wwan_data_new_connection_added_cb (GObject *object,
|
||
GAsyncResult *result,
|
||
gpointer user_data)
|
||
{
|
||
CcWwanData *self;
|
||
CcWwanDataApn *apn;
|
||
g_autoptr(GTask) task = user_data;
|
||
g_autoptr(GError) error = NULL;
|
||
|
||
self = g_task_get_source_object (G_TASK (task));
|
||
apn = g_task_get_task_data (G_TASK (task));
|
||
apn->remote_connection = nm_client_add_connection_finish (self->nm_client,
|
||
result, &error);
|
||
if (!error)
|
||
{
|
||
apn->modified = FALSE;
|
||
|
||
/* If APN has access method, it’s already on the list */
|
||
if (!apn->access_method)
|
||
{
|
||
g_list_store_append (self->apn_list, apn);
|
||
g_object_unref (apn);
|
||
}
|
||
|
||
g_task_return_pointer (task, apn, NULL);
|
||
}
|
||
else
|
||
{
|
||
g_task_return_error (task, g_steal_pointer (&error));
|
||
}
|
||
}
|
||
|
||
void
|
||
cc_wwan_data_save_apn (CcWwanData *self,
|
||
CcWwanDataApn *apn,
|
||
GCancellable *cancellable,
|
||
GAsyncReadyCallback callback,
|
||
gpointer user_data)
|
||
{
|
||
NMConnection *connection = NULL;
|
||
g_autoptr(GTask) task = NULL;
|
||
|
||
g_return_if_fail (CC_IS_WWAN_DATA (self));
|
||
g_return_if_fail (CC_IS_WWAN_DATA_APN (apn));
|
||
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
||
task = g_task_new (self, cancellable, callback, user_data);
|
||
g_task_set_task_data (task, apn, NULL);
|
||
|
||
connection = wwan_data_get_nm_connection (apn);
|
||
|
||
/* If the item has a remote connection, it should already be saved.
|
||
* We should save it again only if it got modified */
|
||
if (apn->remote_connection && !apn->modified)
|
||
{
|
||
g_task_return_pointer (task, apn, NULL);
|
||
return;
|
||
}
|
||
|
||
wwan_data_update_apn (self, apn, connection);
|
||
if (wwan_data_apn_is_new (apn))
|
||
{
|
||
nm_client_add_connection_async (self->nm_client, apn->nm_connection,
|
||
TRUE, cancellable,
|
||
cc_wwan_data_new_connection_added_cb,
|
||
g_steal_pointer (&task));
|
||
}
|
||
else
|
||
{
|
||
nm_remote_connection_commit_changes_async (apn->remote_connection, TRUE,
|
||
cancellable,
|
||
cc_wwan_data_connection_updated_cb,
|
||
g_steal_pointer (&task));
|
||
}
|
||
}
|
||
|
||
CcWwanDataApn *
|
||
cc_wwan_data_save_apn_finish (CcWwanData *self,
|
||
GAsyncResult *result,
|
||
GError **error)
|
||
{
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL);
|
||
g_return_val_if_fail (G_IS_TASK (result), NULL);
|
||
|
||
return g_task_propagate_pointer (G_TASK (result), error);
|
||
}
|
||
|
||
static void
|
||
cc_wwan_data_activated_cb (GObject *object,
|
||
GAsyncResult *result,
|
||
gpointer user_data)
|
||
{
|
||
CcWwanData *self;
|
||
NMActiveConnection *connection;
|
||
g_autoptr(GTask) task = user_data;
|
||
g_autoptr(GError) error = NULL;
|
||
|
||
self = g_task_get_source_object (G_TASK (task));
|
||
connection = nm_client_activate_connection_finish (self->nm_client,
|
||
result, &error);
|
||
if (connection)
|
||
{
|
||
g_set_object (&self->active_connection, connection);
|
||
g_task_return_boolean (task, TRUE);
|
||
}
|
||
else
|
||
{
|
||
g_task_return_error (task, g_steal_pointer (&error));
|
||
}
|
||
|
||
if (error)
|
||
g_warning ("Error: %s", error->message);
|
||
}
|
||
|
||
static void
|
||
cc_wwan_data_settings_saved_cb (GObject *object,
|
||
GAsyncResult *result,
|
||
gpointer user_data)
|
||
{
|
||
CcWwanData *self;
|
||
GCancellable *cancellable;
|
||
g_autoptr(GTask) task = user_data;
|
||
g_autoptr(GError) error = NULL;
|
||
|
||
self = g_task_get_source_object (G_TASK (task));
|
||
cancellable = g_task_get_cancellable (G_TASK (task));
|
||
|
||
if (!cc_wwan_data_save_apn_finish (self, result, &error))
|
||
{
|
||
g_task_return_error (task, g_steal_pointer (&error));
|
||
return;
|
||
}
|
||
|
||
self->default_apn->modified = FALSE;
|
||
|
||
if (self->data_enabled)
|
||
{
|
||
nm_client_activate_connection_async (self->nm_client,
|
||
NM_CONNECTION (self->default_apn->remote_connection),
|
||
self->nm_device,
|
||
NULL, cancellable,
|
||
cc_wwan_data_activated_cb,
|
||
g_steal_pointer (&task));
|
||
}
|
||
else
|
||
{
|
||
if (nm_device_disconnect (self->nm_device, cancellable, &error))
|
||
{
|
||
g_clear_object (&self->active_connection);
|
||
g_task_return_boolean (task, TRUE);
|
||
}
|
||
else
|
||
{
|
||
g_task_return_error (task, g_steal_pointer (&error));
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* cc_wwan_data_save_settings:
|
||
* @cancellable: (nullable): a #GCancellable or %NULL
|
||
* @callback: a #GAsyncReadyCallback, or %NULL
|
||
* @user_data: closure data for @callback
|
||
*
|
||
* Save default settings to disk and apply changes.
|
||
* If the default APN has data enabled, the data is
|
||
* activated after the settings are saved.
|
||
*
|
||
* It’s a programmer error to call this function without
|
||
* a default APN set.
|
||
* Finish with cc_wwan_data_save_settings_finish().
|
||
*/
|
||
void
|
||
cc_wwan_data_save_settings (CcWwanData *self,
|
||
GCancellable *cancellable,
|
||
GAsyncReadyCallback callback,
|
||
gpointer user_data)
|
||
{
|
||
NMConnection *connection;
|
||
NMSetting *setting;
|
||
g_autoptr(GTask) task = NULL;
|
||
|
||
g_return_if_fail (CC_IS_WWAN_DATA (self));
|
||
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
g_return_if_fail (self->default_apn != NULL);
|
||
|
||
task = g_task_new (self, cancellable, callback, user_data);
|
||
|
||
/* Reset old settings to default value */
|
||
if (self->old_default_apn && self->old_default_apn->remote_connection)
|
||
{
|
||
connection = NM_CONNECTION (self->old_default_apn->remote_connection);
|
||
|
||
setting = NM_SETTING (nm_connection_get_setting_gsm (connection));
|
||
g_object_set (G_OBJECT (setting),
|
||
NM_SETTING_GSM_HOME_ONLY, TRUE,
|
||
NM_SETTING_GSM_SIM_ID, NULL,
|
||
NULL);
|
||
|
||
setting = NM_SETTING (nm_connection_get_setting_ip4_config (connection));
|
||
g_object_set (setting,
|
||
NM_SETTING_IP_CONFIG_DNS_PRIORITY, CC_WWAN_DNS_PRIORITY_LOW,
|
||
NM_SETTING_IP_CONFIG_ROUTE_METRIC, (gint64)CC_WWAN_ROUTE_PRIORITY_LOW,
|
||
NULL);
|
||
|
||
setting = NM_SETTING (nm_connection_get_setting_connection (connection));
|
||
g_object_set (G_OBJECT (setting),
|
||
NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
|
||
NULL);
|
||
|
||
nm_remote_connection_commit_changes (NM_REMOTE_CONNECTION (connection),
|
||
TRUE, cancellable, NULL);
|
||
self->old_default_apn->modified = FALSE;
|
||
self->old_default_apn = NULL;
|
||
}
|
||
|
||
self->default_apn->modified = TRUE;
|
||
connection = wwan_data_get_nm_connection (self->default_apn);
|
||
|
||
setting = NM_SETTING (nm_connection_get_setting_gsm (connection));
|
||
g_object_set (G_OBJECT (setting),
|
||
NM_SETTING_GSM_HOME_ONLY, self->home_only,
|
||
NM_SETTING_GSM_SIM_ID, self->sim_id,
|
||
NULL);
|
||
|
||
cc_wwan_data_save_apn (self, self->default_apn, cancellable,
|
||
cc_wwan_data_settings_saved_cb,
|
||
g_steal_pointer (&task));
|
||
}
|
||
|
||
gboolean
|
||
cc_wwan_data_save_settings_finish (CcWwanData *self,
|
||
GAsyncResult *result,
|
||
GError **error)
|
||
{
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE);
|
||
g_return_val_if_fail (G_IS_TASK (result), FALSE);
|
||
|
||
return g_task_propagate_boolean (G_TASK (result), error);
|
||
}
|
||
|
||
gboolean
|
||
cc_wwan_data_delete_apn (CcWwanData *self,
|
||
CcWwanDataApn *apn,
|
||
GCancellable *cancellable,
|
||
GError **error)
|
||
{
|
||
NMRemoteConnection *connection = NULL;
|
||
gboolean ret = FALSE;
|
||
gint apn_index;
|
||
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE);
|
||
g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), FALSE);
|
||
g_return_val_if_fail (error != NULL, FALSE);
|
||
|
||
apn_index = wwan_data_get_apn_index (self, apn);
|
||
if (apn_index == -1)
|
||
{
|
||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||
"APN not found for the connection");
|
||
return FALSE;
|
||
}
|
||
|
||
connection = g_steal_pointer (&apn->remote_connection);
|
||
wwan_data_apn_reset (apn);
|
||
|
||
if (connection)
|
||
ret = nm_remote_connection_delete (connection, cancellable, error);
|
||
|
||
if (!ret)
|
||
{
|
||
apn->remote_connection = connection;
|
||
*error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
|
||
"Deleting APN from NetworkManager failed");
|
||
return ret;
|
||
}
|
||
|
||
g_object_unref (connection);
|
||
|
||
/* We remove the item only if it's not in the mobile provider database */
|
||
if (!apn->access_method)
|
||
{
|
||
if (self->default_apn == apn)
|
||
self->default_apn = NULL;
|
||
|
||
g_list_store_remove (self->apn_list, apn_index);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
*error = g_error_new (G_IO_ERROR, G_IO_ERROR_READ_ONLY,
|
||
"Deleting APN from NetworkManager failed");
|
||
return FALSE;
|
||
}
|
||
|
||
CcWwanDataApn *
|
||
cc_wwan_data_get_default_apn (CcWwanData *self)
|
||
{
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL);
|
||
|
||
return self->default_apn;
|
||
}
|
||
|
||
gboolean
|
||
cc_wwan_data_set_default_apn (CcWwanData *self,
|
||
CcWwanDataApn *apn)
|
||
{
|
||
NMConnection *connection;
|
||
NMSetting *setting;
|
||
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE);
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), FALSE);
|
||
g_return_val_if_fail (self->sim_id != NULL, FALSE);
|
||
|
||
if (self->default_apn == apn)
|
||
return FALSE;
|
||
|
||
/*
|
||
* APNs are bound to the SIM, not the modem device.
|
||
* This will let the APN work if the same SIM inserted
|
||
* in a different device, and not enable data if a
|
||
* different SIM is inserted to the modem.
|
||
*/
|
||
apn->modified = TRUE;
|
||
self->old_default_apn = self->default_apn;
|
||
self->default_apn = apn;
|
||
connection = wwan_data_get_nm_connection (apn);
|
||
setting = NM_SETTING (nm_connection_get_setting_gsm (connection));
|
||
g_object_set (G_OBJECT (setting),
|
||
NM_SETTING_GSM_SIM_ID, self->sim_id, NULL);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
gboolean
|
||
cc_wwan_data_get_enabled (CcWwanData *self)
|
||
{
|
||
NMSettingConnection *setting;
|
||
NMConnection *connection;
|
||
NMDeviceState state;
|
||
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE);
|
||
|
||
state = nm_device_get_state (self->nm_device);
|
||
|
||
if (state == NM_DEVICE_STATE_DISCONNECTED ||
|
||
state == NM_DEVICE_STATE_DEACTIVATING)
|
||
if (nm_device_get_state_reason (self->nm_device) == NM_DEVICE_STATE_REASON_USER_REQUESTED)
|
||
return FALSE;
|
||
|
||
if (nm_device_get_active_connection (self->nm_device) != NULL)
|
||
return TRUE;
|
||
|
||
if (!self->default_apn || !self->default_apn->remote_connection)
|
||
return FALSE;
|
||
|
||
connection = NM_CONNECTION (self->default_apn->remote_connection);
|
||
setting = nm_connection_get_setting_connection (connection);
|
||
|
||
return nm_setting_connection_get_autoconnect (setting);
|
||
}
|
||
|
||
/**
|
||
* cc_wwan_data_set_enabled:
|
||
* @self: A #CcWwanData
|
||
* @enable_data: whether to enable data
|
||
*
|
||
* Enable data for the device. The settings is
|
||
* saved to disk only after a default APN is set.
|
||
*
|
||
* If the data is enabled, the device will automatically
|
||
* turn data on everytime the same SIM is available.
|
||
* The data set is bound to the SIM, not the modem device.
|
||
*
|
||
* Use @cc_wwan_data_save_apn() with the default APN
|
||
* to save the changes and really enable/disable data.
|
||
*/
|
||
void
|
||
cc_wwan_data_set_enabled (CcWwanData *self,
|
||
gboolean enable_data)
|
||
{
|
||
g_return_if_fail (CC_IS_WWAN_DATA (self));
|
||
|
||
self->data_enabled = !!enable_data;
|
||
|
||
if (self->default_apn)
|
||
self->default_apn->modified = TRUE;
|
||
}
|
||
|
||
gboolean
|
||
cc_wwan_data_get_roaming_enabled (CcWwanData *self)
|
||
{
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE);
|
||
|
||
if (!self->default_apn)
|
||
return FALSE;
|
||
|
||
return !self->home_only;
|
||
}
|
||
|
||
/**
|
||
* cc_wwan_data_apn_set_roaming_enabled:
|
||
* @self: A #CcWwanData
|
||
* @enable_roaming: whether to enable roaming or not
|
||
*
|
||
* Enable roaming for the device. The settings is
|
||
* saved to disk only after a default APN is set.
|
||
*
|
||
* Use @cc_wwan_data_save_apn() with the default APN
|
||
* to save the changes and really enable/disable data.
|
||
*/
|
||
void
|
||
cc_wwan_data_set_roaming_enabled (CcWwanData *self,
|
||
gboolean enable_roaming)
|
||
{
|
||
g_return_if_fail (CC_IS_WWAN_DATA (self));
|
||
|
||
self->home_only = !enable_roaming;
|
||
|
||
if (self->default_apn)
|
||
self->default_apn->modified = TRUE;
|
||
}
|
||
|
||
static void
|
||
cc_wwan_data_apn_finalize (GObject *object)
|
||
{
|
||
CcWwanDataApn *apn = CC_WWAN_DATA_APN (object);
|
||
|
||
wwan_data_apn_reset (apn);
|
||
g_clear_pointer (&apn->access_method,
|
||
nma_mobile_access_method_unref);
|
||
|
||
G_OBJECT_CLASS (cc_wwan_data_parent_class)->finalize (object);
|
||
}
|
||
|
||
static void
|
||
cc_wwan_data_apn_class_init (CcWwanDataApnClass *klass)
|
||
{
|
||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
|
||
object_class->finalize = cc_wwan_data_apn_finalize;
|
||
}
|
||
|
||
static void
|
||
cc_wwan_data_apn_init (CcWwanDataApn *apn)
|
||
{
|
||
}
|
||
|
||
CcWwanDataApn *
|
||
cc_wwan_data_apn_new (void)
|
||
{
|
||
return g_object_new (CC_TYPE_WWAN_DATA_APN, NULL);
|
||
}
|
||
|
||
/**
|
||
* cc_wwan_data_apn_get_name:
|
||
* @apn: A #CcWwanDataApn
|
||
*
|
||
* Get the Name of @apn
|
||
*
|
||
* Returns: (transfer none): The Name of @apn
|
||
*/
|
||
const gchar *
|
||
cc_wwan_data_apn_get_name (CcWwanDataApn *apn)
|
||
{
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), "");
|
||
|
||
if (apn->remote_connection)
|
||
return nm_connection_get_id (NM_CONNECTION (apn->remote_connection));
|
||
|
||
if (apn->access_method)
|
||
return nma_mobile_access_method_get_name (apn->access_method);
|
||
|
||
return "";
|
||
}
|
||
|
||
/**
|
||
* cc_wwan_data_apn_set_name:
|
||
* @apn: A #CcWwanDataApn
|
||
* @name: The name to be given for APN, should not
|
||
* be empty
|
||
*
|
||
* Set the name of @apn to be @name.
|
||
*
|
||
* @apn is only modified, use @cc_wwan_data_save_apn()
|
||
* to save the changes.
|
||
*/
|
||
void
|
||
cc_wwan_data_apn_set_name (CcWwanDataApn *apn,
|
||
const gchar *name)
|
||
{
|
||
NMConnection *connection;
|
||
NMSettingConnection *setting;
|
||
|
||
g_return_if_fail (CC_IS_WWAN_DATA_APN (apn));
|
||
g_return_if_fail (name != NULL);
|
||
g_return_if_fail (*name != '\0');
|
||
|
||
if (g_str_equal (cc_wwan_data_apn_get_name (apn), name))
|
||
return;
|
||
|
||
apn->modified = TRUE;
|
||
connection = wwan_data_get_nm_connection (apn);
|
||
setting = nm_connection_get_setting_connection (connection);
|
||
g_object_set (G_OBJECT (setting),
|
||
NM_SETTING_CONNECTION_ID, name,
|
||
NULL);
|
||
}
|
||
|
||
/**
|
||
* cc_wwan_data_apn_get_apn:
|
||
* @apn: A #CcWwanDataApn
|
||
*
|
||
* Get the APN of @apn
|
||
*
|
||
* Returns: (transfer none): The APN of @apn
|
||
*/
|
||
const gchar *
|
||
cc_wwan_data_apn_get_apn (CcWwanDataApn *apn)
|
||
{
|
||
const gchar *apn_name = "";
|
||
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), "");
|
||
|
||
if (apn->remote_connection)
|
||
{
|
||
NMSettingGsm *setting;
|
||
|
||
setting = nm_connection_get_setting_gsm (NM_CONNECTION (apn->remote_connection));
|
||
apn_name = nm_setting_gsm_get_apn (setting);
|
||
}
|
||
else if (apn->access_method)
|
||
{
|
||
apn_name = nma_mobile_access_method_get_3gpp_apn (apn->access_method);
|
||
}
|
||
|
||
return apn_name ? apn_name : "";
|
||
}
|
||
|
||
/**
|
||
* cc_wwan_data_apn_set_apn:
|
||
* @apn: A #CcWwanDataApn
|
||
* @apn_name: The apn to be used, should not be
|
||
* empty
|
||
*
|
||
* Set the APN of @apn to @apn_name. @apn_name is
|
||
* usually a URL like “example.com” or a simple string
|
||
* like “internet”
|
||
*
|
||
* @apn is only modified, use @cc_wwan_data_save_apn()
|
||
* to save the changes.
|
||
*/
|
||
void
|
||
cc_wwan_data_apn_set_apn (CcWwanDataApn *apn,
|
||
const gchar *apn_name)
|
||
{
|
||
NMConnection *connection;
|
||
NMSettingGsm *setting;
|
||
|
||
g_return_if_fail (CC_IS_WWAN_DATA_APN (apn));
|
||
g_return_if_fail (apn_name != NULL);
|
||
g_return_if_fail (*apn_name != '\0');
|
||
|
||
if (g_str_equal (cc_wwan_data_apn_get_apn (apn), apn_name))
|
||
return;
|
||
|
||
apn->modified = TRUE;
|
||
connection = wwan_data_get_nm_connection (apn);
|
||
setting = nm_connection_get_setting_gsm (connection);
|
||
g_object_set (G_OBJECT (setting),
|
||
NM_SETTING_GSM_APN, apn_name,
|
||
NULL);
|
||
}
|
||
|
||
/**
|
||
* cc_wwan_data_apn_get_username:
|
||
* @apn: A #CcWwanDataApn
|
||
*
|
||
* Get the Username of @apn
|
||
*
|
||
* Returns: (transfer none): The Username of @apn
|
||
*/
|
||
const gchar *
|
||
cc_wwan_data_apn_get_username (CcWwanDataApn *apn)
|
||
{
|
||
const gchar *username = "";
|
||
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), "");
|
||
|
||
if (apn->remote_connection)
|
||
{
|
||
NMSettingGsm *setting;
|
||
|
||
setting = nm_connection_get_setting_gsm (NM_CONNECTION (apn->remote_connection));
|
||
username = nm_setting_gsm_get_username (setting);
|
||
}
|
||
else if (apn->access_method)
|
||
{
|
||
username = nma_mobile_access_method_get_username (apn->access_method);
|
||
}
|
||
|
||
return username ? username : "";
|
||
}
|
||
|
||
/**
|
||
* cc_wwan_data_apn_set_username:
|
||
* @apn: A #CcWwanDataAPN
|
||
* @username: The username to be used
|
||
*
|
||
* Set the Username of @apn to @username.
|
||
*
|
||
* @apn is only modified, use @cc_wwan_data_save_apn()
|
||
* to save the changes.
|
||
*/
|
||
void
|
||
cc_wwan_data_apn_set_username (CcWwanDataApn *apn,
|
||
const gchar *username)
|
||
{
|
||
NMConnection *connection;
|
||
NMSettingGsm *setting;
|
||
|
||
g_return_if_fail (CC_IS_WWAN_DATA_APN (apn));
|
||
|
||
if (username && !*username)
|
||
username = NULL;
|
||
|
||
if (g_strcmp0 (cc_wwan_data_apn_get_username (apn), username) == 0)
|
||
return;
|
||
|
||
apn->modified = TRUE;
|
||
connection = wwan_data_get_nm_connection (apn);
|
||
setting = nm_connection_get_setting_gsm (connection);
|
||
g_object_set (G_OBJECT (setting),
|
||
NM_SETTING_GSM_USERNAME, username,
|
||
NULL);
|
||
}
|
||
|
||
/**
|
||
* cc_wwan_data_apn_get_password:
|
||
* @apn: A #CcWwanDataApn
|
||
*
|
||
* Get the Password of @apn
|
||
*
|
||
* Returns: (transfer none): The Password of @apn
|
||
*/
|
||
const gchar *
|
||
cc_wwan_data_apn_get_password (CcWwanDataApn *apn)
|
||
{
|
||
const gchar *password = "";
|
||
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), "");
|
||
|
||
if (NM_IS_REMOTE_CONNECTION (apn->remote_connection))
|
||
{
|
||
g_autoptr(GVariant) secrets = NULL;
|
||
g_autoptr(GError) error = NULL;
|
||
|
||
secrets = nm_remote_connection_get_secrets (NM_REMOTE_CONNECTION (apn->remote_connection),
|
||
"gsm", NULL, &error);
|
||
|
||
if (!error)
|
||
nm_connection_update_secrets (NM_CONNECTION (apn->remote_connection),
|
||
"gsm", secrets, &error);
|
||
|
||
if (error)
|
||
{
|
||
g_warning ("Error: %s", error->message);
|
||
return "";
|
||
}
|
||
}
|
||
|
||
if (apn->remote_connection)
|
||
{
|
||
NMSettingGsm *setting;
|
||
|
||
setting = nm_connection_get_setting_gsm (NM_CONNECTION (apn->remote_connection));
|
||
password = nm_setting_gsm_get_password (setting);
|
||
}
|
||
else if (apn->access_method)
|
||
{
|
||
password = nma_mobile_access_method_get_password (apn->access_method);
|
||
}
|
||
|
||
return password ? password : "";
|
||
|
||
if (apn->remote_connection)
|
||
nm_connection_clear_secrets (NM_CONNECTION (apn->remote_connection));
|
||
}
|
||
|
||
/**
|
||
* cc_wwan_data_apn_set_password:
|
||
* @apn: A #CcWwanDataApn
|
||
* @password: The password to be used
|
||
*
|
||
* Set the Password of @apn to @password.
|
||
*
|
||
* @apn is only modified, use @cc_wwan_data_save_apn()
|
||
* to save the changes.
|
||
*/
|
||
void
|
||
cc_wwan_data_apn_set_password (CcWwanDataApn *apn,
|
||
const gchar *password)
|
||
{
|
||
NMConnection *connection;
|
||
NMSettingGsm *setting;
|
||
|
||
g_return_if_fail (CC_IS_WWAN_DATA_APN (apn));
|
||
|
||
if (password && !*password)
|
||
password = NULL;
|
||
|
||
if (g_strcmp0 (cc_wwan_data_apn_get_password (apn), password) == 0)
|
||
return;
|
||
|
||
apn->modified = TRUE;
|
||
connection = wwan_data_get_nm_connection (apn);
|
||
setting = nm_connection_get_setting_gsm (connection);
|
||
g_object_set (G_OBJECT (setting),
|
||
NM_SETTING_GSM_PASSWORD, password,
|
||
NULL);
|
||
}
|
||
|
||
gint
|
||
cc_wwan_data_get_priority (CcWwanData *self)
|
||
{
|
||
CcWwanDataApn *apn;
|
||
NMSettingIPConfig *setting;
|
||
|
||
g_return_val_if_fail (CC_IS_WWAN_DATA (self),
|
||
CC_WWAN_APN_PRIORITY_LOW);
|
||
|
||
apn = self->default_apn;
|
||
|
||
if (!apn || !apn->remote_connection)
|
||
return CC_WWAN_APN_PRIORITY_LOW;
|
||
|
||
setting = nm_connection_get_setting_ip4_config (NM_CONNECTION (apn->remote_connection));
|
||
|
||
/* Lower the number, higher the priority */
|
||
if (nm_setting_ip_config_get_route_metric (setting) <= CC_WWAN_ROUTE_PRIORITY_HIGH)
|
||
return CC_WWAN_APN_PRIORITY_HIGH;
|
||
else
|
||
return CC_WWAN_APN_PRIORITY_LOW;
|
||
}
|
||
|
||
void
|
||
cc_wwan_data_set_priority (CcWwanData *self,
|
||
int priority)
|
||
{
|
||
g_return_if_fail (CC_IS_WWAN_DATA (self));
|
||
g_return_if_fail (priority == CC_WWAN_APN_PRIORITY_LOW ||
|
||
priority == CC_WWAN_APN_PRIORITY_HIGH);
|
||
|
||
if (self->priority == priority)
|
||
return;
|
||
|
||
self->priority = priority;
|
||
|
||
if (self->default_apn)
|
||
self->default_apn->modified = TRUE;
|
||
}
|