GCC Code Coverage Report


Directory: ./
File: panels/wwan/cc-wwan-data.c
Date: 2024-05-03 09:46:52
Exec Total Coverage
Lines: 0 545 0.0%
Functions: 0 56 0.0%
Branches: 0 425 0.0%

Line Branch Exec Source
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* cc-wwan-data.c
3 *
4 * Copyright 2019 Purism SPC
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author(s):
20 * Mohammed Sadiq <sadiq@sadiqpk.org>
21 *
22 * SPDX-License-Identifier: GPL-3.0-or-later
23 */
24
25 #undef G_LOG_DOMAIN
26 #define G_LOG_DOMAIN "cc-wwan-data"
27
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31
32 #define _GNU_SOURCE
33 #include <string.h>
34 #include <glib/gi18n.h>
35 #include <nma-mobile-providers.h>
36
37 #include "cc-wwan-data.h"
38
39 /**
40 * @short_description: Device Internet Data Object
41 * @include: "cc-wwan-device-data.h"
42 *
43 * #CcWwanData represents the data object of the given
44 * #CcWwanDevice. Please note that while #CcWWanDevice
45 * is bound to the hardware device, #CcWwanData may also
46 * depend on the inserted SIM (if supported). So the state
47 * of #CcWwanData changes when SIM is changed.
48 */
49
50 /*
51 * Priority for connections. The larger the number, the lower the priority
52 * https://developer.gnome.org/NetworkManager/stable/nm-settings.html:
53 *
54 * A lower value is better (higher priority). Zero selects a globally
55 * configured default value. If the latter is missing or zero too, it
56 * defaults to 50 for VPNs and 100 for other connections.
57 *
58 * Since WiFi and other network connections will likely get the default
59 * setting of 100, set WWAN DNS priorities higher than the default, with
60 * room to allow multiple modems to set priority above/below each other.
61 */
62 #define CC_WWAN_DNS_PRIORITY_LOW (120)
63 #define CC_WWAN_DNS_PRIORITY_HIGH (115)
64
65 /* These are to be set as route metric */
66 #define CC_WWAN_ROUTE_PRIORITY_LOW (1050)
67 #define CC_WWAN_ROUTE_PRIORITY_HIGH (1040)
68
69 struct _CcWwanData
70 {
71 GObject parent_instance;
72
73 MMObject *mm_object;
74 MMModem *modem;
75 MMSim *sim;
76 gchar *sim_id;
77
78 gchar *operator_code; /* MCCMNC */
79 GError *error;
80
81 NMClient *nm_client;
82 NMDevice *nm_device;
83 NMAMobileProvidersDatabase *apn_db;
84 NMAMobileProvider *apn_provider;
85 CcWwanDataApn *default_apn;
86 CcWwanDataApn *old_default_apn;
87 GListStore *apn_list;
88 NMActiveConnection *active_connection;
89
90 gint priority;
91 gboolean data_enabled; /* autoconnect enabled */
92 gboolean home_only; /* Data roaming */
93 gboolean apn_list_updated; /* APN list updated from mobile-provider-info */
94 };
95
96 G_DEFINE_TYPE (CcWwanData, cc_wwan_data, G_TYPE_OBJECT)
97
98 /*
99 * Default Access Point Settings Logic:
100 * For a provided SIM, all the APNs available from NetworkManager
101 * that matches the given SIM identifier (ICCID, available via
102 * mm_sim_get_identifier() or similar gdbus API) is loaded for
103 * the Device (In NetworkManager, it is saved as ‘sim-id’, if
104 * present). At a time, only one connection will be bound to
105 * a device. If there are more than one match, the item with
106 * the highest ‘route-metric’ is taken. If more matches are
107 * still available, the first item is chosen.
108 *
109 * Populating All available APNs:
110 * All Possible APNs for the given sim are populated the following
111 * way (A list of all the following avoiding duplicates)
112 * 1. The above mentioned “Default Access Point Settings Logic”
113 * 2. Get All saved Network Manager connections with the
114 * provided MCCMNC of the given SIM
115 * 3. Get All possible APNs for the MCCMNC from mobile-provider-info
116 *
117 * Testing if data is enabled:
118 * Check if any of the items from step 1 have ‘autoconnect’ set
119 *
120 * Checking/Setting current SIM for data (in case of multiple SIM):
121 * Since other networks (like wifi, ethernet) should have higher
122 * priorities we use a negative number for priority.
123 * 1. All APNs by default have priority CC_WWAN_APN_PRIORITY_LOW
124 * 2. APN of selected SIM for active data have priority of
125 * CC_WWAN_APN_PRIORITY_HIGH
126 *
127 * XXX: Since users may create custom APNs via nmtui or like tools
128 * we may have to check if there are some inconsistencies with APNs
129 * available in NetworkManager, and ask user if they have to reset
130 * the APNs that have invalid settings (basically, we care only APNs
131 * that are set to have ‘autoconnect’ enabled, and all we need is to
132 * disable autoconnect). We won’t interfere CDMA/EVDO networks.
133 */
134 struct _CcWwanDataApn {
135 GObject parent_instance;
136
137 /* Set if the APN is from the mobile-provider-info database */
138 NMAMobileAccessMethod *access_method;
139
140 /* Set if the APN is saved in NetworkManager */
141 NMConnection *nm_connection;
142 NMRemoteConnection *remote_connection;
143
144 gboolean modified;
145 };
146
147 G_DEFINE_TYPE (CcWwanDataApn, cc_wwan_data_apn, G_TYPE_OBJECT)
148
149 enum {
150 PROP_0,
151 PROP_ERROR,
152 PROP_ENABLED,
153 N_PROPS
154 };
155
156 static GParamSpec *properties[N_PROPS];
157
158 static void
159 wwan_data_apn_reset (CcWwanDataApn *apn)
160 {
161 if (!apn)
162 return;
163
164 g_clear_object (&apn->nm_connection);
165 g_clear_object (&apn->remote_connection);
166 }
167
168 static NMConnection *
169 wwan_data_get_nm_connection (CcWwanDataApn *apn)
170 {
171 NMConnection *connection;
172 NMSetting *setting;
173 g_autofree gchar *uuid = NULL;
174
175 if (apn->nm_connection)
176 return apn->nm_connection;
177
178 if (apn->remote_connection)
179 return NM_CONNECTION (apn->remote_connection);
180
181 connection = nm_simple_connection_new ();
182 apn->nm_connection = connection;
183
184 setting = nm_setting_connection_new ();
185 uuid = nm_utils_uuid_generate ();
186 g_object_set (setting,
187 NM_SETTING_CONNECTION_UUID, uuid,
188 NM_SETTING_CONNECTION_TYPE, NM_SETTING_GSM_SETTING_NAME,
189 NULL);
190 nm_connection_add_setting (connection, setting);
191
192 setting = nm_setting_serial_new ();
193 nm_connection_add_setting (connection, setting);
194
195 setting = nm_setting_ip4_config_new ();
196 g_object_set (setting, NM_SETTING_IP_CONFIG_METHOD, "auto", NULL);
197 nm_connection_add_setting (connection, setting);
198
199 nm_connection_add_setting (connection, nm_setting_gsm_new ());
200 nm_connection_add_setting (connection, nm_setting_ppp_new ());
201
202 return apn->nm_connection;
203 }
204
205 static gboolean
206 wwan_data_apn_are_same (CcWwanDataApn *apn,
207 NMAMobileAccessMethod *access_method)
208 {
209 NMConnection *connection;
210 NMSetting *setting;
211
212 if (!apn->remote_connection)
213 return FALSE;
214
215 connection = NM_CONNECTION (apn->remote_connection);
216 setting = NM_SETTING (nm_connection_get_setting_gsm (connection));
217
218 if (g_strcmp0 (nma_mobile_access_method_get_3gpp_apn (access_method),
219 nm_setting_gsm_get_apn (NM_SETTING_GSM (setting))) != 0)
220 return FALSE;
221
222 if (g_strcmp0 (nma_mobile_access_method_get_username (access_method),
223 nm_setting_gsm_get_username (NM_SETTING_GSM (setting))) != 0)
224 return FALSE;
225
226 if (g_strcmp0 (nma_mobile_access_method_get_password (access_method),
227 cc_wwan_data_apn_get_password (apn)) != 0)
228 return FALSE;
229
230 return TRUE;
231 }
232
233 static CcWwanDataApn *
234 wwan_data_find_matching_apn (CcWwanData *self,
235 NMAMobileAccessMethod *access_method)
236 {
237 CcWwanDataApn *apn;
238 guint i, n_items;
239
240 n_items = g_list_model_get_n_items (G_LIST_MODEL (self->apn_list));
241
242 for (i = 0; i < n_items; i++)
243 {
244 apn = g_list_model_get_item (G_LIST_MODEL (self->apn_list), i);
245
246 if (apn->access_method == access_method)
247 return apn;
248
249 if (wwan_data_apn_are_same (apn, access_method))
250 return apn;
251
252 g_object_unref (apn);
253 }
254
255 return NULL;
256 }
257
258 static gboolean
259 wwan_data_nma_method_is_mms (NMAMobileAccessMethod *method)
260 {
261 const char *str;
262
263 str = nma_mobile_access_method_get_3gpp_apn (method);
264 if (str && strcasestr (str, "mms"))
265 return TRUE;
266
267 str = nma_mobile_access_method_get_name (method);
268 if (str && strcasestr (str, "mms"))
269 return TRUE;
270
271 return FALSE;
272 }
273
274 static void
275 wwan_data_update_apn_list_db (CcWwanData *self)
276 {
277 GSList *apn_methods = NULL, *l;
278 g_autoptr(GError) error = NULL;
279 guint i = 0;
280
281 if (!self->sim || !self->operator_code || self->apn_list_updated)
282 return;
283
284 if (!self->apn_list)
285 return;
286
287 if (!self->apn_db)
288 self->apn_db = nma_mobile_providers_database_new_sync (NULL, NULL, NULL, &error);
289
290 if (error)
291 {
292 g_warning ("%s", error->message);
293 return;
294 }
295
296 if (!self->apn_provider)
297 self->apn_provider = nma_mobile_providers_database_lookup_3gpp_mcc_mnc (self->apn_db,
298 self->operator_code);
299
300 if (self->apn_provider)
301 apn_methods = nma_mobile_provider_get_methods (self->apn_provider);
302
303 self->apn_list_updated = TRUE;
304
305 for (l = apn_methods; l; l = l->next, i++)
306 {
307 g_autoptr(CcWwanDataApn) apn = NULL;
308
309 /* We don’t list MMS APNs */
310 if (wwan_data_nma_method_is_mms (l->data))
311 continue;
312
313 apn = wwan_data_find_matching_apn (self, l->data);
314
315 /* Prepend the item in order */
316 if (!apn)
317 {
318 apn = cc_wwan_data_apn_new ();
319 apn->access_method = l->data;
320 g_list_store_insert (self->apn_list, i, apn);
321 }
322
323 apn->access_method = l->data;
324 }
325 }
326
327 static void
328 wwan_data_update_apn_list (CcWwanData *self)
329 {
330 const GPtrArray *nm_connections;
331 guint i;
332
333 if (self->apn_list || !self->sim || !self->nm_device ||
334 nm_device_get_state (self->nm_device) <= NM_DEVICE_STATE_UNAVAILABLE)
335 return;
336
337 if (!self->apn_list)
338 self->apn_list = g_list_store_new (CC_TYPE_WWAN_DATA_APN);
339
340 if (self->nm_device)
341 {
342 nm_connections = nm_device_get_available_connections (self->nm_device);
343
344 for (i = 0; i < nm_connections->len; i++)
345 {
346 g_autoptr(CcWwanDataApn) apn = NULL;
347
348 apn = cc_wwan_data_apn_new ();
349 apn->remote_connection = g_object_ref (nm_connections->pdata[i]);
350 g_list_store_append (self->apn_list, apn);
351
352 /* Load the default APN */
353 if (!self->default_apn && self->sim_id)
354 {
355 NMSettingConnection *connection_setting;
356 NMSettingIPConfig *ip_setting;
357 NMSettingGsm *setting;
358 NMConnection *connection;
359 const gchar *sim_id;
360
361 connection = NM_CONNECTION (apn->remote_connection);
362 setting = nm_connection_get_setting_gsm (connection);
363 connection_setting = nm_connection_get_setting_connection (connection);
364 sim_id = nm_setting_gsm_get_sim_id (setting);
365
366 if (sim_id && *sim_id && g_str_equal (sim_id, self->sim_id))
367 {
368 self->default_apn = apn;
369 self->home_only = nm_setting_gsm_get_home_only (setting);
370 self->data_enabled = nm_setting_connection_get_autoconnect (connection_setting);
371
372 /* If any of the APN has a high priority, the device have high priority */
373 ip_setting = nm_connection_get_setting_ip4_config (connection);
374 if (nm_setting_ip_config_get_route_metric (ip_setting) == CC_WWAN_ROUTE_PRIORITY_HIGH)
375 self->priority = CC_WWAN_APN_PRIORITY_HIGH;
376 }
377 }
378 }
379 }
380 }
381
382 static void
383 wwan_device_state_changed_cb (CcWwanData *self)
384 {
385 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ENABLED]);
386 }
387
388 static void
389 wwan_device_3gpp_operator_code_changd_cb (CcWwanData *self)
390 {
391 MMModem3gpp *modem_3gpp;
392
393 modem_3gpp = mm_object_peek_modem_3gpp (self->mm_object);
394
395 if (!self->operator_code)
396 {
397 self->operator_code = mm_modem_3gpp_dup_operator_code (modem_3gpp);
398
399 if (self->operator_code)
400 {
401 wwan_data_update_apn_list (self);
402 wwan_data_update_apn_list_db (self);
403 }
404 }
405 }
406
407 static void
408 cc_wwan_data_get_property (GObject *object,
409 guint prop_id,
410 GValue *value,
411 GParamSpec *pspec)
412 {
413 CcWwanData *self = (CcWwanData *)object;
414
415 switch (prop_id)
416 {
417 case PROP_ERROR:
418 g_value_set_boolean (value, self->error != NULL);
419 break;
420
421 case PROP_ENABLED:
422 g_value_set_boolean (value, cc_wwan_data_get_enabled (self));
423 break;
424
425 default:
426 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
427 }
428 }
429
430 static void
431 cc_wwan_data_dispose (GObject *object)
432 {
433 CcWwanData *self = (CcWwanData *)object;
434
435 g_clear_pointer (&self->sim_id, g_free);
436 g_clear_pointer (&self->operator_code, g_free);
437 g_clear_error (&self->error);
438 g_clear_object (&self->apn_list);
439 g_clear_object (&self->modem);
440 g_clear_object (&self->mm_object);
441 g_clear_object (&self->nm_client);
442 g_clear_object (&self->active_connection);
443 g_clear_object (&self->apn_db);
444
445 G_OBJECT_CLASS (cc_wwan_data_parent_class)->dispose (object);
446 }
447
448 static void
449 cc_wwan_data_class_init (CcWwanDataClass *klass)
450 {
451 GObjectClass *object_class = G_OBJECT_CLASS (klass);
452
453 object_class->get_property = cc_wwan_data_get_property;
454 object_class->dispose = cc_wwan_data_dispose;
455
456 properties[PROP_ERROR] =
457 g_param_spec_boolean ("error",
458 "Error",
459 "Set if some Error occurs",
460 FALSE,
461 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
462
463 properties[PROP_ENABLED] =
464 g_param_spec_boolean ("enabled",
465 "Enabled",
466 "Get if the data is enabled",
467 FALSE,
468 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
469
470 g_object_class_install_properties (object_class, N_PROPS, properties);
471 }
472
473 static void
474 cc_wwan_data_init (CcWwanData *self)
475 {
476 self->home_only = TRUE;
477 self->priority = CC_WWAN_APN_PRIORITY_LOW;
478 }
479
480 /**
481 * cc_wwan_data_new:
482 * @mm_object: An #MMObject
483 * @nm_client: An #NMClient
484 *
485 * Create a new device data representing the given
486 * @mm_object. If @mm_object isn’t a 3G/CDMA/LTE
487 * modem, %NULL will be returned
488 *
489 * Returns: A #CcWwanData or %NULL.
490 */
491 CcWwanData *
492 cc_wwan_data_new (MMObject *mm_object,
493 NMClient *nm_client)
494 {
495 CcWwanData *self;
496 NMDevice *nm_device = NULL;
497 g_autoptr(MMModem) modem = NULL;
498 NMDeviceModemCapabilities capabilities = 0;
499
500 g_return_val_if_fail (MM_IS_OBJECT (mm_object), NULL);
501 g_return_val_if_fail (NM_CLIENT (nm_client), NULL);
502
503 modem = mm_object_get_modem (mm_object);
504
505 if (modem)
506 nm_device = nm_client_get_device_by_iface (nm_client,
507 mm_modem_get_primary_port (modem));
508
509 if (NM_IS_DEVICE_MODEM (nm_device))
510 capabilities = nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (nm_device));
511
512 if (!(capabilities & (NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS
513 | NM_DEVICE_MODEM_CAPABILITY_LTE)))
514 return NULL;
515
516 self = g_object_new (CC_TYPE_WWAN_DATA, NULL);
517
518 self->nm_client = g_object_ref (nm_client);
519 self->mm_object = g_object_ref (mm_object);
520 self->modem = g_steal_pointer (&modem);
521 self->sim = mm_modem_get_sim_sync (self->modem, NULL, NULL);
522 self->sim_id = mm_sim_dup_identifier (self->sim);
523 self->operator_code = mm_sim_dup_operator_identifier (self->sim);
524 self->nm_device = g_object_ref (nm_device);
525 self->active_connection = nm_device_get_active_connection (nm_device);
526
527 if (!self->operator_code)
528 {
529 MMModem3gpp *modem_3gpp;
530
531 modem_3gpp = mm_object_peek_modem_3gpp (mm_object);
532 if (modem_3gpp)
533 {
534 g_signal_connect_object (modem_3gpp, "notify::operator-code",
535 G_CALLBACK (wwan_device_3gpp_operator_code_changd_cb),
536 self, G_CONNECT_SWAPPED);
537 wwan_device_3gpp_operator_code_changd_cb (self);
538 }
539 }
540
541 if (self->active_connection)
542 g_object_ref (self->active_connection);
543
544 g_signal_connect_object (self->nm_device, "notify::state",
545 G_CALLBACK (wwan_device_state_changed_cb),
546 self, G_CONNECT_SWAPPED);
547
548 wwan_data_update_apn_list (self);
549 wwan_data_update_apn_list_db (self);
550
551 return self;
552 }
553
554 GError *
555 cc_wwan_data_get_error (CcWwanData *self)
556 {
557 g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL);
558
559 return self->error;
560 }
561
562 const gchar *
563 cc_wwan_data_get_simple_html_error (CcWwanData *self)
564 {
565 g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL);
566
567 if (!self->error)
568 return NULL;
569
570 if (g_error_matches (self->error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
571 return _("Operation Cancelled");
572
573 if (g_error_matches (self->error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED))
574 return _("<b>Error:</b> Access denied changing settings");
575
576 if (self->error->domain == MM_MOBILE_EQUIPMENT_ERROR)
577 return _("<b>Error:</b> Mobile Equipment Error");
578
579 return NULL;
580 }
581
582 GListModel *
583 cc_wwan_data_get_apn_list (CcWwanData *self)
584 {
585 g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL);
586
587 if (!self->apn_list)
588 wwan_data_update_apn_list (self);
589
590 return G_LIST_MODEL (self->apn_list);
591 }
592
593 static gboolean
594 wwan_data_apn_is_new (CcWwanDataApn *apn)
595 {
596 return apn->remote_connection == NULL;
597 }
598
599 static void
600 wwan_data_update_apn (CcWwanData *self,
601 CcWwanDataApn *apn,
602 NMConnection *connection)
603 {
604 NMSetting *setting;
605 const gchar *name, *username, *password, *apn_name;
606 gint dns_priority, route_metric;
607
608 setting = NM_SETTING (nm_connection_get_setting_connection (connection));
609
610 g_object_set (setting,
611 NM_SETTING_CONNECTION_AUTOCONNECT, self->data_enabled,
612 NULL);
613
614 setting = NM_SETTING (nm_connection_get_setting_gsm (connection));
615
616 g_object_set (setting,
617 NM_SETTING_GSM_HOME_ONLY, self->home_only,
618 NULL);
619
620 setting = NM_SETTING (nm_connection_get_setting_ip4_config (connection));
621 if (self->priority == CC_WWAN_APN_PRIORITY_HIGH &&
622 self->default_apn == apn)
623 {
624 dns_priority = CC_WWAN_DNS_PRIORITY_HIGH;
625 route_metric = CC_WWAN_ROUTE_PRIORITY_HIGH;
626 }
627 else
628 {
629 dns_priority = CC_WWAN_DNS_PRIORITY_LOW;
630 route_metric = CC_WWAN_ROUTE_PRIORITY_LOW;
631 }
632
633 g_object_set (setting,
634 NM_SETTING_IP_CONFIG_DNS_PRIORITY, dns_priority,
635 NM_SETTING_IP_CONFIG_ROUTE_METRIC, (gint64)route_metric,
636 NULL);
637
638 if (apn->access_method && !apn->remote_connection)
639 {
640 name = nma_mobile_access_method_get_name (apn->access_method);
641 username = nma_mobile_access_method_get_username (apn->access_method);
642 password = nma_mobile_access_method_get_password (apn->access_method);
643 apn_name = nma_mobile_access_method_get_3gpp_apn (apn->access_method);
644 }
645 else
646 {
647 return;
648 }
649
650 setting = NM_SETTING (nm_connection_get_setting_gsm (connection));
651 g_object_set (setting,
652 NM_SETTING_GSM_USERNAME, username,
653 NM_SETTING_GSM_PASSWORD, password,
654 NM_SETTING_GSM_APN, apn_name,
655 NULL);
656
657 setting = NM_SETTING (nm_connection_get_setting_connection (connection));
658
659 g_object_set (setting,
660 NM_SETTING_CONNECTION_ID, name,
661 NULL);
662 }
663
664 static gint
665 wwan_data_get_apn_index (CcWwanData *self,
666 CcWwanDataApn *apn)
667 {
668 GListModel *model;
669 guint i, n_items;
670
671 model = G_LIST_MODEL (self->apn_list);
672 n_items = g_list_model_get_n_items (model);
673
674 for (i = 0; i < n_items; i++)
675 {
676 g_autoptr(CcWwanDataApn) cached_apn = NULL;
677
678 cached_apn = g_list_model_get_item (model, i);
679
680 if (apn == cached_apn)
681 return i;
682 }
683
684 return -1;
685 }
686
687 static void
688 cc_wwan_data_connection_updated_cb (GObject *object,
689 GAsyncResult *result,
690 gpointer user_data)
691 {
692 CcWwanData *self;
693 CcWwanDataApn *apn;
694 g_autoptr(GTask) task = user_data;
695 g_autoptr(GError) error = NULL;
696
697 self = g_task_get_source_object (G_TASK (task));
698 apn = g_task_get_task_data (G_TASK (task));
699
700 nm_remote_connection_commit_changes_finish (apn->remote_connection,
701 result, &error);
702 if (!error)
703 {
704 guint apn_index;
705 apn_index = wwan_data_get_apn_index (self, apn);
706
707 if (apn_index >= 0)
708 g_list_model_items_changed (G_LIST_MODEL (self->apn_list),
709 apn_index, 1, 1);
710 else
711 g_warning ("APN ‘%s’ not in APN list",
712 cc_wwan_data_apn_get_name (apn));
713
714 apn->modified = FALSE;
715 g_task_return_boolean (task, TRUE);
716 }
717 else
718 {
719 g_task_return_error (task, g_steal_pointer (&error));
720 }
721 }
722
723 static void
724 cc_wwan_data_new_connection_added_cb (GObject *object,
725 GAsyncResult *result,
726 gpointer user_data)
727 {
728 CcWwanData *self;
729 CcWwanDataApn *apn;
730 g_autoptr(GTask) task = user_data;
731 g_autoptr(GError) error = NULL;
732
733 self = g_task_get_source_object (G_TASK (task));
734 apn = g_task_get_task_data (G_TASK (task));
735 apn->remote_connection = nm_client_add_connection_finish (self->nm_client,
736 result, &error);
737 if (!error)
738 {
739 apn->modified = FALSE;
740
741 /* If APN has access method, it’s already on the list */
742 if (!apn->access_method)
743 {
744 g_list_store_append (self->apn_list, apn);
745 g_object_unref (apn);
746 }
747
748 g_task_return_pointer (task, apn, NULL);
749 }
750 else
751 {
752 g_task_return_error (task, g_steal_pointer (&error));
753 }
754 }
755
756 void
757 cc_wwan_data_save_apn (CcWwanData *self,
758 CcWwanDataApn *apn,
759 GCancellable *cancellable,
760 GAsyncReadyCallback callback,
761 gpointer user_data)
762 {
763 NMConnection *connection = NULL;
764 g_autoptr(GTask) task = NULL;
765
766 g_return_if_fail (CC_IS_WWAN_DATA (self));
767 g_return_if_fail (CC_IS_WWAN_DATA_APN (apn));
768 g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
769
770 task = g_task_new (self, cancellable, callback, user_data);
771 g_task_set_task_data (task, apn, NULL);
772
773 connection = wwan_data_get_nm_connection (apn);
774
775 /* If the item has a remote connection, it should already be saved.
776 * We should save it again only if it got modified */
777 if (apn->remote_connection && !apn->modified)
778 {
779 g_task_return_pointer (task, apn, NULL);
780 return;
781 }
782
783 wwan_data_update_apn (self, apn, connection);
784 if (wwan_data_apn_is_new (apn))
785 {
786 nm_client_add_connection_async (self->nm_client, apn->nm_connection,
787 TRUE, cancellable,
788 cc_wwan_data_new_connection_added_cb,
789 g_steal_pointer (&task));
790 }
791 else
792 {
793 nm_remote_connection_commit_changes_async (apn->remote_connection, TRUE,
794 cancellable,
795 cc_wwan_data_connection_updated_cb,
796 g_steal_pointer (&task));
797 }
798 }
799
800 CcWwanDataApn *
801 cc_wwan_data_save_apn_finish (CcWwanData *self,
802 GAsyncResult *result,
803 GError **error)
804 {
805 g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL);
806 g_return_val_if_fail (G_IS_TASK (result), NULL);
807
808 return g_task_propagate_pointer (G_TASK (result), error);
809 }
810
811 static void
812 cc_wwan_data_activated_cb (GObject *object,
813 GAsyncResult *result,
814 gpointer user_data)
815 {
816 CcWwanData *self;
817 NMActiveConnection *connection;
818 g_autoptr(GTask) task = user_data;
819 g_autoptr(GError) error = NULL;
820
821 self = g_task_get_source_object (G_TASK (task));
822 connection = nm_client_activate_connection_finish (self->nm_client,
823 result, &error);
824 if (connection)
825 {
826 g_set_object (&self->active_connection, connection);
827 g_task_return_boolean (task, TRUE);
828 }
829 else
830 {
831 g_task_return_error (task, g_steal_pointer (&error));
832 }
833
834 if (error)
835 g_warning ("Error: %s", error->message);
836 }
837
838 static void
839 cc_wwan_data_disconnect_cb (GObject *object,
840 GAsyncResult *result,
841 gpointer user_data)
842 {
843 CcWwanData *self;
844 g_autoptr(GTask) task = user_data;
845 g_autoptr(GError) error = NULL;
846
847 self = g_task_get_source_object (G_TASK (task));
848 if (nm_device_disconnect_finish (self->nm_device, result, &error))
849 {
850 g_clear_object (&self->active_connection);
851 g_task_return_boolean (task, TRUE);
852 }
853 else
854 {
855 g_task_return_error (task, g_steal_pointer (&error));
856 }
857
858 if (error)
859 g_warning ("Error: %s", error->message);
860 }
861
862 static void
863 cc_wwan_data_settings_saved_cb (GObject *object,
864 GAsyncResult *result,
865 gpointer user_data)
866 {
867 CcWwanData *self;
868 GCancellable *cancellable;
869 g_autoptr(GTask) task = user_data;
870 g_autoptr(GError) error = NULL;
871
872 self = g_task_get_source_object (G_TASK (task));
873 cancellable = g_task_get_cancellable (G_TASK (task));
874
875 if (!cc_wwan_data_save_apn_finish (self, result, &error))
876 {
877 g_task_return_error (task, g_steal_pointer (&error));
878 return;
879 }
880
881 self->default_apn->modified = FALSE;
882
883 if (self->data_enabled)
884 {
885 nm_client_activate_connection_async (self->nm_client,
886 NM_CONNECTION (self->default_apn->remote_connection),
887 self->nm_device,
888 NULL, cancellable,
889 cc_wwan_data_activated_cb,
890 g_steal_pointer (&task));
891 }
892 else
893 {
894 nm_device_disconnect_async (self->nm_device,
895 cancellable,
896 cc_wwan_data_disconnect_cb,
897 g_steal_pointer (&task));
898 }
899 }
900
901 /**
902 * cc_wwan_data_save_settings:
903 * @cancellable: (nullable): a #GCancellable or %NULL
904 * @callback: a #GAsyncReadyCallback, or %NULL
905 * @user_data: closure data for @callback
906 *
907 * Save default settings to disk and apply changes.
908 * If the default APN has data enabled, the data is
909 * activated after the settings are saved.
910 *
911 * It’s a programmer error to call this function without
912 * a default APN set.
913 * Finish with cc_wwan_data_save_settings_finish().
914 */
915 void
916 cc_wwan_data_save_settings (CcWwanData *self,
917 GCancellable *cancellable,
918 GAsyncReadyCallback callback,
919 gpointer user_data)
920 {
921 NMConnection *connection;
922 NMSetting *setting;
923 g_autoptr(GTask) task = NULL;
924
925 g_return_if_fail (CC_IS_WWAN_DATA (self));
926 g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
927 g_return_if_fail (self->default_apn != NULL);
928
929 task = g_task_new (self, cancellable, callback, user_data);
930
931 /* Reset old settings to default value */
932 if (self->old_default_apn && self->old_default_apn->remote_connection)
933 {
934 connection = NM_CONNECTION (self->old_default_apn->remote_connection);
935
936 setting = NM_SETTING (nm_connection_get_setting_gsm (connection));
937 g_object_set (G_OBJECT (setting),
938 NM_SETTING_GSM_HOME_ONLY, TRUE,
939 NM_SETTING_GSM_SIM_ID, NULL,
940 NULL);
941
942 setting = NM_SETTING (nm_connection_get_setting_ip4_config (connection));
943 g_object_set (setting,
944 NM_SETTING_IP_CONFIG_DNS_PRIORITY, CC_WWAN_DNS_PRIORITY_LOW,
945 NM_SETTING_IP_CONFIG_ROUTE_METRIC, (gint64)CC_WWAN_ROUTE_PRIORITY_LOW,
946 NULL);
947
948 setting = NM_SETTING (nm_connection_get_setting_connection (connection));
949 g_object_set (G_OBJECT (setting),
950 NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
951 NULL);
952
953 nm_remote_connection_commit_changes (NM_REMOTE_CONNECTION (connection),
954 TRUE, cancellable, NULL);
955 self->old_default_apn->modified = FALSE;
956 self->old_default_apn = NULL;
957 }
958
959 self->default_apn->modified = TRUE;
960 connection = wwan_data_get_nm_connection (self->default_apn);
961
962 setting = NM_SETTING (nm_connection_get_setting_gsm (connection));
963 g_object_set (G_OBJECT (setting),
964 NM_SETTING_GSM_HOME_ONLY, self->home_only,
965 NM_SETTING_GSM_SIM_ID, self->sim_id,
966 NULL);
967
968 cc_wwan_data_save_apn (self, self->default_apn, cancellable,
969 cc_wwan_data_settings_saved_cb,
970 g_steal_pointer (&task));
971 }
972
973 gboolean
974 cc_wwan_data_save_settings_finish (CcWwanData *self,
975 GAsyncResult *result,
976 GError **error)
977 {
978 g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE);
979 g_return_val_if_fail (G_IS_TASK (result), FALSE);
980
981 return g_task_propagate_boolean (G_TASK (result), error);
982 }
983
984 gboolean
985 cc_wwan_data_delete_apn (CcWwanData *self,
986 CcWwanDataApn *apn,
987 GCancellable *cancellable,
988 GError **error)
989 {
990 NMRemoteConnection *connection = NULL;
991 gboolean ret = FALSE;
992 gint apn_index;
993
994 g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE);
995 g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
996 g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), FALSE);
997 g_return_val_if_fail (error != NULL, FALSE);
998
999 apn_index = wwan_data_get_apn_index (self, apn);
1000 if (apn_index == -1)
1001 {
1002 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
1003 "APN not found for the connection");
1004 return FALSE;
1005 }
1006
1007 connection = g_steal_pointer (&apn->remote_connection);
1008 wwan_data_apn_reset (apn);
1009
1010 if (connection)
1011 ret = nm_remote_connection_delete (connection, cancellable, error);
1012
1013 if (!ret)
1014 {
1015 apn->remote_connection = connection;
1016 *error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
1017 "Deleting APN from NetworkManager failed");
1018 return ret;
1019 }
1020
1021 g_object_unref (connection);
1022
1023 /* We remove the item only if it's not in the mobile provider database */
1024 if (!apn->access_method)
1025 {
1026 if (self->default_apn == apn)
1027 self->default_apn = NULL;
1028
1029 g_list_store_remove (self->apn_list, apn_index);
1030
1031 return TRUE;
1032 }
1033
1034 *error = g_error_new (G_IO_ERROR, G_IO_ERROR_READ_ONLY,
1035 "Deleting APN from NetworkManager failed");
1036 return FALSE;
1037 }
1038
1039 CcWwanDataApn *
1040 cc_wwan_data_get_default_apn (CcWwanData *self)
1041 {
1042 g_return_val_if_fail (CC_IS_WWAN_DATA (self), NULL);
1043
1044 return self->default_apn;
1045 }
1046
1047 gboolean
1048 cc_wwan_data_set_default_apn (CcWwanData *self,
1049 CcWwanDataApn *apn)
1050 {
1051 NMConnection *connection;
1052 NMSetting *setting;
1053
1054 g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE);
1055 g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), FALSE);
1056
1057 if (self->default_apn == apn)
1058 return FALSE;
1059
1060 /*
1061 * APNs are bound to the SIM, not the modem device.
1062 * This will let the APN work if the same SIM inserted
1063 * in a different device, and not enable data if a
1064 * different SIM is inserted to the modem.
1065 */
1066 apn->modified = TRUE;
1067 self->old_default_apn = self->default_apn;
1068 self->default_apn = apn;
1069 connection = wwan_data_get_nm_connection (apn);
1070 setting = NM_SETTING (nm_connection_get_setting_gsm (connection));
1071
1072 if (self->sim_id)
1073 g_object_set (G_OBJECT (setting),
1074 NM_SETTING_GSM_SIM_ID, self->sim_id, NULL);
1075
1076 return TRUE;
1077 }
1078
1079 gboolean
1080 cc_wwan_data_get_enabled (CcWwanData *self)
1081 {
1082 NMSettingConnection *setting;
1083 NMConnection *connection;
1084 NMDeviceState state;
1085
1086 g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE);
1087
1088 state = nm_device_get_state (self->nm_device);
1089
1090 if (state == NM_DEVICE_STATE_DISCONNECTED ||
1091 state == NM_DEVICE_STATE_DEACTIVATING)
1092 if (nm_device_get_state_reason (self->nm_device) == NM_DEVICE_STATE_REASON_USER_REQUESTED)
1093 return FALSE;
1094
1095 if (nm_device_get_active_connection (self->nm_device) != NULL)
1096 return TRUE;
1097
1098 if (!self->default_apn || !self->default_apn->remote_connection)
1099 return FALSE;
1100
1101 connection = NM_CONNECTION (self->default_apn->remote_connection);
1102 setting = nm_connection_get_setting_connection (connection);
1103
1104 return nm_setting_connection_get_autoconnect (setting);
1105 }
1106
1107 /**
1108 * cc_wwan_data_set_enabled:
1109 * @self: A #CcWwanData
1110 * @enable_data: whether to enable data
1111 *
1112 * Enable data for the device. The settings is
1113 * saved to disk only after a default APN is set.
1114 *
1115 * If the data is enabled, the device will automatically
1116 * turn data on everytime the same SIM is available.
1117 * The data set is bound to the SIM, not the modem device.
1118 *
1119 * Use @cc_wwan_data_save_apn() with the default APN
1120 * to save the changes and really enable/disable data.
1121 */
1122 void
1123 cc_wwan_data_set_enabled (CcWwanData *self,
1124 gboolean enable_data)
1125 {
1126 g_return_if_fail (CC_IS_WWAN_DATA (self));
1127
1128 self->data_enabled = !!enable_data;
1129
1130 if (self->default_apn)
1131 self->default_apn->modified = TRUE;
1132 }
1133
1134 gboolean
1135 cc_wwan_data_get_roaming_enabled (CcWwanData *self)
1136 {
1137 g_return_val_if_fail (CC_IS_WWAN_DATA (self), FALSE);
1138
1139 if (!self->default_apn)
1140 return FALSE;
1141
1142 return !self->home_only;
1143 }
1144
1145 /**
1146 * cc_wwan_data_apn_set_roaming_enabled:
1147 * @self: A #CcWwanData
1148 * @enable_roaming: whether to enable roaming or not
1149 *
1150 * Enable roaming for the device. The settings is
1151 * saved to disk only after a default APN is set.
1152 *
1153 * Use @cc_wwan_data_save_apn() with the default APN
1154 * to save the changes and really enable/disable data.
1155 */
1156 void
1157 cc_wwan_data_set_roaming_enabled (CcWwanData *self,
1158 gboolean enable_roaming)
1159 {
1160 g_return_if_fail (CC_IS_WWAN_DATA (self));
1161
1162 self->home_only = !enable_roaming;
1163
1164 if (self->default_apn)
1165 self->default_apn->modified = TRUE;
1166 }
1167
1168 static void
1169 cc_wwan_data_apn_finalize (GObject *object)
1170 {
1171 CcWwanDataApn *apn = CC_WWAN_DATA_APN (object);
1172
1173 wwan_data_apn_reset (apn);
1174 g_clear_pointer (&apn->access_method,
1175 nma_mobile_access_method_unref);
1176
1177 G_OBJECT_CLASS (cc_wwan_data_parent_class)->finalize (object);
1178 }
1179
1180 static void
1181 cc_wwan_data_apn_class_init (CcWwanDataApnClass *klass)
1182 {
1183 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1184
1185 object_class->finalize = cc_wwan_data_apn_finalize;
1186 }
1187
1188 static void
1189 cc_wwan_data_apn_init (CcWwanDataApn *apn)
1190 {
1191 }
1192
1193 CcWwanDataApn *
1194 cc_wwan_data_apn_new (void)
1195 {
1196 return g_object_new (CC_TYPE_WWAN_DATA_APN, NULL);
1197 }
1198
1199 /**
1200 * cc_wwan_data_apn_get_name:
1201 * @apn: A #CcWwanDataApn
1202 *
1203 * Get the Name of @apn
1204 *
1205 * Returns: (transfer none): The Name of @apn
1206 */
1207 const gchar *
1208 cc_wwan_data_apn_get_name (CcWwanDataApn *apn)
1209 {
1210 g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), "");
1211
1212 if (apn->remote_connection)
1213 return nm_connection_get_id (NM_CONNECTION (apn->remote_connection));
1214
1215 if (apn->access_method)
1216 return nma_mobile_access_method_get_name (apn->access_method);
1217
1218 return "";
1219 }
1220
1221 /**
1222 * cc_wwan_data_apn_set_name:
1223 * @apn: A #CcWwanDataApn
1224 * @name: The name to be given for APN, should not
1225 * be empty
1226 *
1227 * Set the name of @apn to be @name.
1228 *
1229 * @apn is only modified, use @cc_wwan_data_save_apn()
1230 * to save the changes.
1231 */
1232 void
1233 cc_wwan_data_apn_set_name (CcWwanDataApn *apn,
1234 const gchar *name)
1235 {
1236 NMConnection *connection;
1237 NMSettingConnection *setting;
1238
1239 g_return_if_fail (CC_IS_WWAN_DATA_APN (apn));
1240 g_return_if_fail (name != NULL);
1241 g_return_if_fail (*name != '\0');
1242
1243 if (g_str_equal (cc_wwan_data_apn_get_name (apn), name))
1244 return;
1245
1246 apn->modified = TRUE;
1247 connection = wwan_data_get_nm_connection (apn);
1248 setting = nm_connection_get_setting_connection (connection);
1249 g_object_set (G_OBJECT (setting),
1250 NM_SETTING_CONNECTION_ID, name,
1251 NULL);
1252 }
1253
1254 /**
1255 * cc_wwan_data_apn_get_apn:
1256 * @apn: A #CcWwanDataApn
1257 *
1258 * Get the APN of @apn
1259 *
1260 * Returns: (transfer none): The APN of @apn
1261 */
1262 const gchar *
1263 cc_wwan_data_apn_get_apn (CcWwanDataApn *apn)
1264 {
1265 const gchar *apn_name = "";
1266
1267 g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), "");
1268
1269 if (apn->remote_connection)
1270 {
1271 NMSettingGsm *setting;
1272
1273 setting = nm_connection_get_setting_gsm (NM_CONNECTION (apn->remote_connection));
1274 apn_name = nm_setting_gsm_get_apn (setting);
1275 }
1276 else if (apn->access_method)
1277 {
1278 apn_name = nma_mobile_access_method_get_3gpp_apn (apn->access_method);
1279 }
1280
1281 return apn_name ? apn_name : "";
1282 }
1283
1284 /**
1285 * cc_wwan_data_apn_set_apn:
1286 * @apn: A #CcWwanDataApn
1287 * @apn_name: The apn to be used, should not be
1288 * empty
1289 *
1290 * Set the APN of @apn to @apn_name. @apn_name is
1291 * usually a URL like “example.com” or a simple string
1292 * like “internet”
1293 *
1294 * @apn is only modified, use @cc_wwan_data_save_apn()
1295 * to save the changes.
1296 */
1297 void
1298 cc_wwan_data_apn_set_apn (CcWwanDataApn *apn,
1299 const gchar *apn_name)
1300 {
1301 NMConnection *connection;
1302 NMSettingGsm *setting;
1303
1304 g_return_if_fail (CC_IS_WWAN_DATA_APN (apn));
1305 g_return_if_fail (apn_name != NULL);
1306 g_return_if_fail (*apn_name != '\0');
1307
1308 if (g_str_equal (cc_wwan_data_apn_get_apn (apn), apn_name))
1309 return;
1310
1311 apn->modified = TRUE;
1312 connection = wwan_data_get_nm_connection (apn);
1313 setting = nm_connection_get_setting_gsm (connection);
1314 g_object_set (G_OBJECT (setting),
1315 NM_SETTING_GSM_APN, apn_name,
1316 NULL);
1317 }
1318
1319 /**
1320 * cc_wwan_data_apn_get_username:
1321 * @apn: A #CcWwanDataApn
1322 *
1323 * Get the Username of @apn
1324 *
1325 * Returns: (transfer none): The Username of @apn
1326 */
1327 const gchar *
1328 cc_wwan_data_apn_get_username (CcWwanDataApn *apn)
1329 {
1330 const gchar *username = "";
1331
1332 g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), "");
1333
1334 if (apn->remote_connection)
1335 {
1336 NMSettingGsm *setting;
1337
1338 setting = nm_connection_get_setting_gsm (NM_CONNECTION (apn->remote_connection));
1339 username = nm_setting_gsm_get_username (setting);
1340 }
1341 else if (apn->access_method)
1342 {
1343 username = nma_mobile_access_method_get_username (apn->access_method);
1344 }
1345
1346 return username ? username : "";
1347 }
1348
1349 /**
1350 * cc_wwan_data_apn_set_username:
1351 * @apn: A #CcWwanDataAPN
1352 * @username: The username to be used
1353 *
1354 * Set the Username of @apn to @username.
1355 *
1356 * @apn is only modified, use @cc_wwan_data_save_apn()
1357 * to save the changes.
1358 */
1359 void
1360 cc_wwan_data_apn_set_username (CcWwanDataApn *apn,
1361 const gchar *username)
1362 {
1363 NMConnection *connection;
1364 NMSettingGsm *setting;
1365
1366 g_return_if_fail (CC_IS_WWAN_DATA_APN (apn));
1367
1368 if (username && !*username)
1369 username = NULL;
1370
1371 if (g_strcmp0 (cc_wwan_data_apn_get_username (apn), username) == 0)
1372 return;
1373
1374 apn->modified = TRUE;
1375 connection = wwan_data_get_nm_connection (apn);
1376 setting = nm_connection_get_setting_gsm (connection);
1377 g_object_set (G_OBJECT (setting),
1378 NM_SETTING_GSM_USERNAME, username,
1379 NULL);
1380 }
1381
1382 /**
1383 * cc_wwan_data_apn_get_password:
1384 * @apn: A #CcWwanDataApn
1385 *
1386 * Get the Password of @apn
1387 *
1388 * Returns: (transfer none): The Password of @apn
1389 */
1390 const gchar *
1391 cc_wwan_data_apn_get_password (CcWwanDataApn *apn)
1392 {
1393 const gchar *password = "";
1394
1395 g_return_val_if_fail (CC_IS_WWAN_DATA_APN (apn), "");
1396
1397 if (NM_IS_REMOTE_CONNECTION (apn->remote_connection))
1398 {
1399 g_autoptr(GVariant) secrets = NULL;
1400 g_autoptr(GError) error = NULL;
1401
1402 secrets = nm_remote_connection_get_secrets (NM_REMOTE_CONNECTION (apn->remote_connection),
1403 "gsm", NULL, &error);
1404
1405 if (!error)
1406 nm_connection_update_secrets (NM_CONNECTION (apn->remote_connection),
1407 "gsm", secrets, &error);
1408
1409 if (error)
1410 {
1411 g_warning ("Error: %s", error->message);
1412 return "";
1413 }
1414 }
1415
1416 if (apn->remote_connection)
1417 {
1418 NMSettingGsm *setting;
1419
1420 setting = nm_connection_get_setting_gsm (NM_CONNECTION (apn->remote_connection));
1421 password = nm_setting_gsm_get_password (setting);
1422 }
1423 else if (apn->access_method)
1424 {
1425 password = nma_mobile_access_method_get_password (apn->access_method);
1426 }
1427
1428 return password ? password : "";
1429 }
1430
1431 /**
1432 * cc_wwan_data_apn_set_password:
1433 * @apn: A #CcWwanDataApn
1434 * @password: The password to be used
1435 *
1436 * Set the Password of @apn to @password.
1437 *
1438 * @apn is only modified, use @cc_wwan_data_save_apn()
1439 * to save the changes.
1440 */
1441 void
1442 cc_wwan_data_apn_set_password (CcWwanDataApn *apn,
1443 const gchar *password)
1444 {
1445 NMConnection *connection;
1446 NMSettingGsm *setting;
1447
1448 g_return_if_fail (CC_IS_WWAN_DATA_APN (apn));
1449
1450 if (password && !*password)
1451 password = NULL;
1452
1453 if (g_strcmp0 (cc_wwan_data_apn_get_password (apn), password) == 0)
1454 return;
1455
1456 apn->modified = TRUE;
1457 connection = wwan_data_get_nm_connection (apn);
1458 setting = nm_connection_get_setting_gsm (connection);
1459 g_object_set (G_OBJECT (setting),
1460 NM_SETTING_GSM_PASSWORD, password,
1461 NULL);
1462 }
1463
1464 gint
1465 cc_wwan_data_get_priority (CcWwanData *self)
1466 {
1467 CcWwanDataApn *apn;
1468 NMSettingIPConfig *setting;
1469
1470 g_return_val_if_fail (CC_IS_WWAN_DATA (self),
1471 CC_WWAN_APN_PRIORITY_LOW);
1472
1473 apn = self->default_apn;
1474
1475 if (!apn || !apn->remote_connection)
1476 return CC_WWAN_APN_PRIORITY_LOW;
1477
1478 setting = nm_connection_get_setting_ip4_config (NM_CONNECTION (apn->remote_connection));
1479
1480 /* Lower the number, higher the priority */
1481 if (nm_setting_ip_config_get_route_metric (setting) <= CC_WWAN_ROUTE_PRIORITY_HIGH)
1482 return CC_WWAN_APN_PRIORITY_HIGH;
1483 else
1484 return CC_WWAN_APN_PRIORITY_LOW;
1485 }
1486
1487 void
1488 cc_wwan_data_set_priority (CcWwanData *self,
1489 int priority)
1490 {
1491 g_return_if_fail (CC_IS_WWAN_DATA (self));
1492 g_return_if_fail (priority == CC_WWAN_APN_PRIORITY_LOW ||
1493 priority == CC_WWAN_APN_PRIORITY_HIGH);
1494
1495 if (self->priority == priority)
1496 return;
1497
1498 self->priority = priority;
1499
1500 if (self->default_apn)
1501 self->default_apn->modified = TRUE;
1502 }
1503