1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2010-2012 Richard Hughes <richard@hughsie.com>
4 * Copyright (C) 2012 Thomas Bechtold <thomasbechtold@jpberlin.de>
5 * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include <config.h>
23 #include <glib/gi18n.h>
24 #include <stdlib.h>
25
26 #include "shell/cc-object-storage.h"
27
28 #include "cc-network-panel.h"
29 #include "cc-network-resources.h"
30
31 #include <NetworkManager.h>
32
33 #include "net-device-bluetooth.h"
34 #include "net-device-ethernet.h"
35 #include "net-device-mobile.h"
36 #include "net-device-wifi.h"
37 #include "net-proxy.h"
38 #include "net-vpn.h"
39
40 #include "panel-common.h"
41
42 #include "network-dialogs.h"
43 #include "connection-editor/net-connection-editor.h"
44
45 #include <libmm-glib.h>
46
47 typedef enum {
48 OPERATION_NULL,
49 OPERATION_SHOW_DEVICE,
50 OPERATION_CONNECT_MOBILE
51 } CmdlineOperation;
52
53 struct _CcNetworkPanel
54 {
55 CcPanel parent;
56
57 GPtrArray *bluetooth_devices;
58 GPtrArray *ethernet_devices;
59 GPtrArray *mobile_devices;
60 GPtrArray *vpns;
61 GHashTable *nm_device_to_device;
62
63 NMClient *client;
64 MMManager *modem_manager;
65 gboolean updating_device;
66
67 /* widgets */
68 GtkWidget *box_bluetooth;
69 GtkWidget *box_proxy;
70 GtkWidget *box_vpn;
71 GtkWidget *box_wired;
72 GtkWidget *container_bluetooth;
73 GtkWidget *empty_listbox;
74
75 /* wireless dialog stuff */
76 CmdlineOperation arg_operation;
77 gchar *arg_device;
78 gchar *arg_access_point;
79 gboolean operation_done;
80 };
81
82 enum {
83 PROP_0,
84 PROP_PARAMETERS
85 };
86
87 static void handle_argv (CcNetworkPanel *self);
88
CC_PANEL_REGISTER(CcNetworkPanel,cc_network_panel)89 CC_PANEL_REGISTER (CcNetworkPanel, cc_network_panel)
90
91 static void
92 cc_network_panel_get_property (GObject *object,
93 guint property_id,
94 GValue *value,
95 GParamSpec *pspec)
96 {
97 switch (property_id) {
98 default:
99 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
100 }
101 }
102
103 static CmdlineOperation
cmdline_operation_from_string(const gchar * string)104 cmdline_operation_from_string (const gchar *string)
105 {
106 if (g_strcmp0 (string, "connect-3g") == 0)
107 return OPERATION_CONNECT_MOBILE;
108 if (g_strcmp0 (string, "show-device") == 0)
109 return OPERATION_SHOW_DEVICE;
110
111 g_warning ("Invalid additional argument %s", string);
112 return OPERATION_NULL;
113 }
114
115 static void
reset_command_line_args(CcNetworkPanel * self)116 reset_command_line_args (CcNetworkPanel *self)
117 {
118 self->arg_operation = OPERATION_NULL;
119 g_clear_pointer (&self->arg_device, g_free);
120 g_clear_pointer (&self->arg_access_point, g_free);
121 }
122
123 static gboolean
verify_argv(CcNetworkPanel * self,const char ** args)124 verify_argv (CcNetworkPanel *self,
125 const char **args)
126 {
127 switch (self->arg_operation) {
128 case OPERATION_CONNECT_MOBILE:
129 case OPERATION_SHOW_DEVICE:
130 if (self->arg_device == NULL) {
131 g_warning ("Operation %s requires an object path", args[0]);
132 return FALSE;
133 }
134 default:
135 return TRUE;
136 }
137 }
138
139 static GPtrArray *
variant_av_to_string_array(GVariant * array)140 variant_av_to_string_array (GVariant *array)
141 {
142 GVariantIter iter;
143 GVariant *v;
144 GPtrArray *strv;
145 gsize count;
146 count = g_variant_iter_init (&iter, array);
147 strv = g_ptr_array_sized_new (count + 1);
148 while (g_variant_iter_next (&iter, "v", &v)) {
149 g_ptr_array_add (strv, (gpointer)g_variant_get_string (v, NULL));
150 g_variant_unref (v);
151 }
152 g_ptr_array_add (strv, NULL); /* NULL-terminate the strv data array */
153 return strv;
154 }
155
156 static void
cc_network_panel_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)157 cc_network_panel_set_property (GObject *object,
158 guint property_id,
159 const GValue *value,
160 GParamSpec *pspec)
161 {
162 CcNetworkPanel *self = CC_NETWORK_PANEL (object);
163
164 switch (property_id) {
165 case PROP_PARAMETERS: {
166 GVariant *parameters;
167
168 reset_command_line_args (self);
169
170 parameters = g_value_get_variant (value);
171 if (parameters) {
172 g_autoptr(GPtrArray) array = NULL;
173 const gchar **args;
174 array = variant_av_to_string_array (parameters);
175 args = (const gchar **) array->pdata;
176
177 g_debug ("Invoked with operation %s", args[0]);
178
179 if (args[0])
180 self->arg_operation = cmdline_operation_from_string (args[0]);
181 if (args[0] && args[1])
182 self->arg_device = g_strdup (args[1]);
183 if (args[0] && args[1] && args[2])
184 self->arg_access_point = g_strdup (args[2]);
185
186 if (verify_argv (self, (const char **) args) == FALSE) {
187 reset_command_line_args (self);
188 return;
189 }
190 g_debug ("Calling handle_argv() after setting property");
191 handle_argv (self);
192 }
193 break;
194 }
195 default:
196 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
197 }
198 }
199
200 static void
cc_network_panel_dispose(GObject * object)201 cc_network_panel_dispose (GObject *object)
202 {
203 CcNetworkPanel *self = CC_NETWORK_PANEL (object);
204
205 g_clear_object (&self->client);
206 g_clear_object (&self->modem_manager);
207
208 g_clear_pointer (&self->bluetooth_devices, g_ptr_array_unref);
209 g_clear_pointer (&self->ethernet_devices, g_ptr_array_unref);
210 g_clear_pointer (&self->mobile_devices, g_ptr_array_unref);
211 g_clear_pointer (&self->vpns, g_ptr_array_unref);
212 g_clear_pointer (&self->nm_device_to_device, g_hash_table_destroy);
213
214 G_OBJECT_CLASS (cc_network_panel_parent_class)->dispose (object);
215 }
216
217 static void
cc_network_panel_finalize(GObject * object)218 cc_network_panel_finalize (GObject *object)
219 {
220 CcNetworkPanel *self = CC_NETWORK_PANEL (object);
221
222 reset_command_line_args (self);
223
224 G_OBJECT_CLASS (cc_network_panel_parent_class)->finalize (object);
225 }
226
227 static const char *
cc_network_panel_get_help_uri(CcPanel * self)228 cc_network_panel_get_help_uri (CcPanel *self)
229 {
230 return "help:gnome-help/net";
231 }
232
233 static void
panel_refresh_device_titles(CcNetworkPanel * self)234 panel_refresh_device_titles (CcNetworkPanel *self)
235 {
236 g_autoptr(GPtrArray) ndarray = NULL;
237 g_autoptr(GPtrArray) nmdarray = NULL;
238 GtkWidget **devices;
239 NMDevice **nm_devices;
240 g_auto(GStrv) titles = NULL;
241 guint i, num_devices;
242
243 ndarray = g_ptr_array_new ();
244 nmdarray = g_ptr_array_new ();
245 for (i = 0; i < self->bluetooth_devices->len; i++) {
246 NetDeviceBluetooth *device = g_ptr_array_index (self->bluetooth_devices, i);
247 g_ptr_array_add (ndarray, device);
248 g_ptr_array_add (nmdarray, net_device_bluetooth_get_device (device));
249 }
250 for (i = 0; i < self->ethernet_devices->len; i++) {
251 NetDeviceEthernet *device = g_ptr_array_index (self->ethernet_devices, i);
252 g_ptr_array_add (ndarray, device);
253 g_ptr_array_add (nmdarray, net_device_ethernet_get_device (device));
254 }
255 for (i = 0; i < self->mobile_devices->len; i++) {
256 NetDeviceMobile *device = g_ptr_array_index (self->mobile_devices, i);
257 g_ptr_array_add (ndarray, device);
258 g_ptr_array_add (nmdarray, net_device_mobile_get_device (device));
259 }
260
261 if (ndarray->len == 0)
262 return;
263
264 devices = (GtkWidget **)ndarray->pdata;
265 nm_devices = (NMDevice **)nmdarray->pdata;
266 num_devices = ndarray->len;
267
268 titles = nm_device_disambiguate_names (nm_devices, num_devices);
269 for (i = 0; i < num_devices; i++) {
270 if (NM_IS_DEVICE_BT (nm_devices[i]))
271 net_device_bluetooth_set_title (NET_DEVICE_BLUETOOTH (devices[i]), nm_device_bt_get_name (NM_DEVICE_BT (nm_devices[i])));
272 else if (NET_IS_DEVICE_ETHERNET (devices[i]))
273 net_device_ethernet_set_title (NET_DEVICE_ETHERNET (devices[i]), titles[i]);
274 else if (NET_IS_DEVICE_MOBILE (devices[i]))
275 net_device_mobile_set_title (NET_DEVICE_MOBILE (devices[i]), titles[i]);
276 }
277 }
278
279 static gboolean
handle_argv_for_device(CcNetworkPanel * self,NMDevice * device)280 handle_argv_for_device (CcNetworkPanel *self,
281 NMDevice *device)
282 {
283 GtkWidget *toplevel = cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (self)));
284
285 if (self->arg_operation == OPERATION_NULL)
286 return TRUE;
287
288 if (g_strcmp0 (nm_object_get_path (NM_OBJECT (device)), self->arg_device) == 0) {
289 if (self->arg_operation == OPERATION_CONNECT_MOBILE) {
290 cc_network_panel_connect_to_3g_network (toplevel, self->client, device);
291
292 reset_command_line_args (self); /* done */
293 return TRUE;
294 } else if (self->arg_operation == OPERATION_SHOW_DEVICE) {
295 reset_command_line_args (self); /* done */
296 return TRUE;
297 }
298 }
299
300 return FALSE;
301 }
302
303 static gboolean
handle_argv_for_connection(CcNetworkPanel * self,NMConnection * connection)304 handle_argv_for_connection (CcNetworkPanel *self,
305 NMConnection *connection)
306 {
307 if (self->arg_operation == OPERATION_NULL)
308 return TRUE;
309 if (self->arg_operation != OPERATION_SHOW_DEVICE)
310 return FALSE;
311
312 if (g_strcmp0 (nm_connection_get_path (connection), self->arg_device) == 0) {
313 reset_command_line_args (self);
314 return TRUE;
315 }
316
317 return FALSE;
318 }
319
320
321 static void
handle_argv(CcNetworkPanel * self)322 handle_argv (CcNetworkPanel *self)
323 {
324 gint i;
325
326 if (self->arg_operation == OPERATION_NULL)
327 return;
328
329 for (i = 0; i < self->bluetooth_devices->len; i++) {
330 NetDeviceBluetooth *device = g_ptr_array_index (self->bluetooth_devices, i);
331 if (handle_argv_for_device (self, net_device_bluetooth_get_device (device)))
332 return;
333 }
334 for (i = 0; i < self->ethernet_devices->len; i++) {
335 NetDeviceEthernet *device = g_ptr_array_index (self->ethernet_devices, i);
336 if (handle_argv_for_device (self, net_device_ethernet_get_device (device)))
337 return;
338 }
339 for (i = 0; i < self->mobile_devices->len; i++) {
340 NetDeviceMobile *device = g_ptr_array_index (self->mobile_devices, i);
341 if (handle_argv_for_device (self, net_device_mobile_get_device (device)))
342 return;
343 }
344 for (i = 0; i < self->vpns->len; i++) {
345 NetVpn *vpn = g_ptr_array_index (self->vpns, i);
346 if (handle_argv_for_connection (self, net_vpn_get_connection (vpn)))
347 return;
348 }
349
350 g_debug ("Could not handle argv operation, no matching device yet?");
351 }
352
353 /* HACK: this function is basically a workaround. We don't have a single
354 * listbox in the VPN section, thus we need to track the separators and the
355 * stub row manually.
356 */
357 static void
update_vpn_section(CcNetworkPanel * self)358 update_vpn_section (CcNetworkPanel *self)
359 {
360 guint i, n_vpns;
361
362 for (i = 0, n_vpns = 0; i < self->vpns->len; i++) {
363 NetVpn *vpn = g_ptr_array_index (self->vpns, i);
364
365 net_vpn_set_show_separator (vpn, n_vpns > 0);
366 n_vpns++;
367 }
368
369 gtk_widget_set_visible (self->empty_listbox, n_vpns == 0);
370 }
371
372 static void
update_bluetooth_section(CcNetworkPanel * self)373 update_bluetooth_section (CcNetworkPanel *self)
374 {
375 guint i;
376
377 for (i = 0; i < self->bluetooth_devices->len; i++) {
378 NetDeviceBluetooth *device = g_ptr_array_index (self->bluetooth_devices, i);
379 net_device_bluetooth_set_show_separator (device, i > 0);
380 }
381
382 gtk_widget_set_visible (self->container_bluetooth, self->bluetooth_devices->len > 0);
383 }
384
385 static gboolean
wwan_panel_supports_modem(GDBusObject * object)386 wwan_panel_supports_modem (GDBusObject *object)
387 {
388 MMObject *mm_object;
389 MMModem *modem;
390 MMModemCapability capability, supported_capabilities;
391
392 g_assert (G_IS_DBUS_OBJECT (object));
393
394 supported_capabilities = MM_MODEM_CAPABILITY_GSM_UMTS | MM_MODEM_CAPABILITY_LTE;
395 #if MM_CHECK_VERSION (1,14,0)
396 supported_capabilities |= MM_MODEM_CAPABILITY_5GNR;
397 #endif
398
399 mm_object = MM_OBJECT (object);
400 modem = mm_object_get_modem (mm_object);
401 capability = mm_modem_get_current_capabilities (modem);
402
403 return capability & supported_capabilities;
404 }
405
406 static void
panel_add_device(CcNetworkPanel * self,NMDevice * device)407 panel_add_device (CcNetworkPanel *self, NMDevice *device)
408 {
409 NMDeviceType type;
410 NetDeviceEthernet *device_ethernet;
411 NetDeviceMobile *device_mobile;
412 NetDeviceBluetooth *device_bluetooth;
413 g_autoptr(GDBusObject) modem_object = NULL;
414
415 /* does already exist */
416 if (g_hash_table_lookup (self->nm_device_to_device, device) != NULL)
417 return;
418
419 type = nm_device_get_device_type (device);
420
421 g_debug ("device %s type %i path %s",
422 nm_device_get_udi (device), type, nm_object_get_path (NM_OBJECT (device)));
423
424 /* map the NMDeviceType to the GType, or ignore */
425 switch (type) {
426 case NM_DEVICE_TYPE_ETHERNET:
427 case NM_DEVICE_TYPE_INFINIBAND:
428 device_ethernet = net_device_ethernet_new (self->client, device);
429 gtk_widget_show (GTK_WIDGET (device_ethernet));
430 gtk_container_add (GTK_CONTAINER (self->box_wired), GTK_WIDGET (device_ethernet));
431 g_ptr_array_add (self->ethernet_devices, device_ethernet);
432 g_hash_table_insert (self->nm_device_to_device, device, device_ethernet);
433 break;
434 case NM_DEVICE_TYPE_MODEM:
435 if (g_str_has_prefix (nm_device_get_udi (device), "/org/freedesktop/ModemManager1/Modem/")) {
436 if (self->modem_manager == NULL) {
437 g_warning ("Cannot grab information for modem at %s: No ModemManager support",
438 nm_device_get_udi (device));
439 return;
440 }
441
442 modem_object = g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (self->modem_manager),
443 nm_device_get_udi (device));
444 if (modem_object == NULL) {
445 g_warning ("Cannot grab information for modem at %s: Not found",
446 nm_device_get_udi (device));
447 return;
448 }
449
450 /* This will be handled by cellular panel */
451 if (wwan_panel_supports_modem (modem_object))
452 return;
453 }
454
455 device_mobile = net_device_mobile_new (self->client, device, modem_object);
456 gtk_widget_show (GTK_WIDGET (device_mobile));
457 gtk_container_add (GTK_CONTAINER (self->box_wired), GTK_WIDGET (device_mobile));
458 g_ptr_array_add (self->mobile_devices, device_mobile);
459 g_hash_table_insert (self->nm_device_to_device, device, device_mobile);
460 break;
461 case NM_DEVICE_TYPE_BT:
462 device_bluetooth = net_device_bluetooth_new (self->client, device);
463 gtk_widget_show (GTK_WIDGET (device_bluetooth));
464 gtk_container_add (GTK_CONTAINER (self->box_bluetooth), GTK_WIDGET (device_bluetooth));
465 g_ptr_array_add (self->bluetooth_devices, device_bluetooth);
466 g_hash_table_insert (self->nm_device_to_device, device, device_bluetooth);
467
468 /* Update the device_bluetooth section if we're adding a bluetooth
469 * device. This is a temporary solution though, for these will
470 * be handled by the future Mobile Broadband panel */
471 update_bluetooth_section (self);
472 break;
473
474 /* For Wi-Fi and VPN we handle connections separately; we correctly manage
475 * them, but not here.
476 */
477 case NM_DEVICE_TYPE_WIFI:
478 case NM_DEVICE_TYPE_TUN:
479 /* And the rest we simply cannot deal with currently. */
480 default:
481 return;
482 }
483 }
484
485 static void
panel_remove_device(CcNetworkPanel * self,NMDevice * device)486 panel_remove_device (CcNetworkPanel *self, NMDevice *device)
487 {
488 GtkWidget *net_device;
489
490 net_device = g_hash_table_lookup (self->nm_device_to_device, device);
491 if (net_device == NULL)
492 return;
493
494 g_ptr_array_remove (self->bluetooth_devices, net_device);
495 g_ptr_array_remove (self->ethernet_devices, net_device);
496 g_ptr_array_remove (self->mobile_devices, net_device);
497 g_hash_table_remove (self->nm_device_to_device, device);
498
499 gtk_widget_destroy (net_device);
500
501 /* update vpn widgets */
502 update_vpn_section (self);
503
504 /* update device_bluetooth widgets */
505 update_bluetooth_section (self);
506 }
507
508 static void
connection_state_changed(CcNetworkPanel * self)509 connection_state_changed (CcNetworkPanel *self)
510 {
511 }
512
513 static void
active_connections_changed(CcNetworkPanel * self)514 active_connections_changed (CcNetworkPanel *self)
515 {
516 const GPtrArray *connections;
517 int i, j;
518
519 g_debug ("Active connections changed:");
520 connections = nm_client_get_active_connections (self->client);
521 for (i = 0; connections && (i < connections->len); i++) {
522 NMActiveConnection *connection;
523 const GPtrArray *devices;
524
525 connection = g_ptr_array_index (connections, i);
526 g_debug (" %s", nm_object_get_path (NM_OBJECT (connection)));
527 devices = nm_active_connection_get_devices (connection);
528 for (j = 0; devices && j < devices->len; j++)
529 g_debug (" %s", nm_device_get_udi (g_ptr_array_index (devices, j)));
530 if (NM_IS_VPN_CONNECTION (connection))
531 g_debug (" VPN base connection: %s", nm_active_connection_get_specific_object_path (connection));
532
533 if (g_object_get_data (G_OBJECT (connection), "has-state-changed-handler") == NULL) {
534 g_signal_connect_object (connection, "notify::state",
535 G_CALLBACK (connection_state_changed), self, G_CONNECT_SWAPPED);
536 g_object_set_data (G_OBJECT (connection), "has-state-changed-handler", GINT_TO_POINTER (TRUE));
537 }
538 }
539 }
540
541 static void
device_managed_cb(CcNetworkPanel * self,GParamSpec * pspec,NMDevice * device)542 device_managed_cb (CcNetworkPanel *self, GParamSpec *pspec, NMDevice *device)
543 {
544 if (!nm_device_get_managed (device))
545 return;
546
547 panel_add_device (self, device);
548 panel_refresh_device_titles (self);
549 }
550
551 static void
device_added_cb(CcNetworkPanel * self,NMDevice * device)552 device_added_cb (CcNetworkPanel *self, NMDevice *device)
553 {
554 g_debug ("New device added");
555
556 if (nm_device_get_managed (device))
557 device_managed_cb (self, NULL, device);
558 else
559 g_signal_connect_object (device, "notify::managed", G_CALLBACK (device_managed_cb), self, G_CONNECT_SWAPPED);
560 }
561
562 static void
device_removed_cb(CcNetworkPanel * self,NMDevice * device)563 device_removed_cb (CcNetworkPanel *self, NMDevice *device)
564 {
565 g_debug ("Device removed");
566 panel_remove_device (self, device);
567 panel_refresh_device_titles (self);
568
569 g_signal_handlers_disconnect_by_func (device,
570 G_CALLBACK (device_managed_cb),
571 self);
572 }
573
574 static void
manager_running(CcNetworkPanel * self)575 manager_running (CcNetworkPanel *self)
576 {
577 const GPtrArray *devices;
578 int i;
579
580 /* clear all devices we added */
581 if (!nm_client_get_nm_running (self->client)) {
582 g_debug ("NM disappeared");
583 goto out;
584 }
585
586 g_debug ("coldplugging devices");
587 devices = nm_client_get_devices (self->client);
588 if (devices == NULL) {
589 g_debug ("No devices to add");
590 return;
591 }
592 for (i = 0; i < devices->len; i++) {
593 NMDevice *device = g_ptr_array_index (devices, i);
594 device_added_cb (self, device);
595 }
596 out:
597 panel_refresh_device_titles (self);
598
599 g_debug ("Calling handle_argv() after cold-plugging devices");
600 handle_argv (self);
601 }
602
603 static void
panel_add_vpn_device(CcNetworkPanel * self,NMConnection * connection)604 panel_add_vpn_device (CcNetworkPanel *self, NMConnection *connection)
605 {
606 NetVpn *net_vpn;
607 guint i;
608
609 /* does already exist */
610 for (i = 0; i < self->vpns->len; i++) {
611 net_vpn = g_ptr_array_index (self->vpns, i);
612 if (net_vpn_get_connection (net_vpn) == connection)
613 return;
614 }
615
616 net_vpn = net_vpn_new (self->client, connection);
617 gtk_widget_show (GTK_WIDGET (net_vpn));
618 gtk_container_add (GTK_CONTAINER (self->box_vpn), GTK_WIDGET (net_vpn));
619
620 /* store in the devices array */
621 g_ptr_array_add (self->vpns, net_vpn);
622
623 /* update vpn widgets */
624 update_vpn_section (self);
625 }
626
627 static void
add_connection(CcNetworkPanel * self,NMConnection * connection)628 add_connection (CcNetworkPanel *self, NMConnection *connection)
629 {
630 NMSettingConnection *s_con;
631 const gchar *type, *iface;
632
633 s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection,
634 NM_TYPE_SETTING_CONNECTION));
635 type = nm_setting_connection_get_connection_type (s_con);
636 iface = nm_connection_get_interface_name (connection);
637 if (g_strcmp0 (type, "vpn") != 0 && iface == NULL)
638 return;
639
640 /* Don't add the libvirtd bridge to the UI */
641 if (g_strcmp0 (nm_setting_connection_get_interface_name (s_con), "virbr0") == 0)
642 return;
643
644 g_debug ("add %s/%s remote connection: %s",
645 type, g_type_name_from_instance ((GTypeInstance*)connection),
646 nm_connection_get_path (connection));
647 if (!iface)
648 panel_add_vpn_device (self, connection);
649 }
650
651 static void
client_connection_removed_cb(CcNetworkPanel * self,NMConnection * connection)652 client_connection_removed_cb (CcNetworkPanel *self, NMConnection *connection)
653 {
654 guint i;
655
656 for (i = 0; i < self->vpns->len; i++) {
657 NetVpn *vpn = g_ptr_array_index (self->vpns, i);
658 if (net_vpn_get_connection (vpn) == connection) {
659 g_ptr_array_remove (self->vpns, vpn);
660 gtk_widget_destroy (GTK_WIDGET (vpn));
661 update_vpn_section (self);
662 return;
663 }
664 }
665 }
666
667 static void
panel_check_network_manager_version(CcNetworkPanel * self)668 panel_check_network_manager_version (CcNetworkPanel *self)
669 {
670 const gchar *version;
671
672 /* parse running version */
673 version = nm_client_get_version (self->client);
674 if (version == NULL) {
675 GtkWidget *box;
676 GtkWidget *label;
677 g_autofree gchar *markup = NULL;
678
679 gtk_container_remove (GTK_CONTAINER (self), gtk_bin_get_child (GTK_BIN (self)));
680
681 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 20);
682 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
683 gtk_widget_set_vexpand (box, TRUE);
684 gtk_container_add (GTK_CONTAINER (self), box);
685
686 label = gtk_label_new (_("Oops, something has gone wrong. Please contact your software vendor."));
687 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
688 gtk_widget_set_valign (label, GTK_ALIGN_END);
689 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
690
691 markup = g_strdup_printf ("<small><tt>%s</tt></small>",
692 _("NetworkManager needs to be running."));
693 label = gtk_label_new (NULL);
694 gtk_label_set_markup (GTK_LABEL (label), markup);
695 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
696 gtk_widget_set_valign (label, GTK_ALIGN_START);
697 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
698
699 gtk_widget_show_all (box);
700 } else {
701 manager_running (self);
702 }
703 }
704
705 static void
create_connection_cb(GtkWidget * button,CcNetworkPanel * self)706 create_connection_cb (GtkWidget *button,
707 CcNetworkPanel *self)
708 {
709 NetConnectionEditor *editor;
710
711 editor = net_connection_editor_new (NULL, NULL, NULL, self->client);
712 gtk_window_set_transient_for (GTK_WINDOW (editor), GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))));
713 gtk_window_present (GTK_WINDOW (editor));
714 }
715
716 static void
on_toplevel_map(GtkWidget * widget,CcNetworkPanel * self)717 on_toplevel_map (GtkWidget *widget,
718 CcNetworkPanel *self)
719 {
720 /* is the user compiling against a new version, but not running
721 * the daemon? */
722 panel_check_network_manager_version (self);
723 }
724
725
726 static void
cc_network_panel_class_init(CcNetworkPanelClass * klass)727 cc_network_panel_class_init (CcNetworkPanelClass *klass)
728 {
729 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
730 GObjectClass *object_class = G_OBJECT_CLASS (klass);
731 CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
732
733 panel_class->get_help_uri = cc_network_panel_get_help_uri;
734
735 object_class->get_property = cc_network_panel_get_property;
736 object_class->set_property = cc_network_panel_set_property;
737 object_class->dispose = cc_network_panel_dispose;
738 object_class->finalize = cc_network_panel_finalize;
739
740 g_object_class_override_property (object_class, PROP_PARAMETERS, "parameters");
741
742 gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/network/cc-network-panel.ui");
743
744 gtk_widget_class_bind_template_child (widget_class, CcNetworkPanel, box_bluetooth);
745 gtk_widget_class_bind_template_child (widget_class, CcNetworkPanel, box_proxy);
746 gtk_widget_class_bind_template_child (widget_class, CcNetworkPanel, box_vpn);
747 gtk_widget_class_bind_template_child (widget_class, CcNetworkPanel, box_wired);
748 gtk_widget_class_bind_template_child (widget_class, CcNetworkPanel, container_bluetooth);
749 gtk_widget_class_bind_template_child (widget_class, CcNetworkPanel, empty_listbox);
750
751 gtk_widget_class_bind_template_callback (widget_class, create_connection_cb);
752 }
753
754 static void
cc_network_panel_init(CcNetworkPanel * self)755 cc_network_panel_init (CcNetworkPanel *self)
756 {
757 NetProxy *proxy;
758 g_autoptr(GError) error = NULL;
759 GtkWidget *toplevel;
760 g_autoptr(GDBusConnection) system_bus = NULL;
761 const GPtrArray *connections;
762 guint i;
763
764 g_resources_register (cc_network_get_resource ());
765
766 gtk_widget_init_template (GTK_WIDGET (self));
767
768 self->bluetooth_devices = g_ptr_array_new ();
769 self->ethernet_devices = g_ptr_array_new ();
770 self->mobile_devices = g_ptr_array_new ();
771 self->vpns = g_ptr_array_new ();
772 self->nm_device_to_device = g_hash_table_new (g_direct_hash, g_direct_equal);
773
774 /* add the virtual proxy device */
775 proxy = net_proxy_new ();
776 gtk_widget_show (GTK_WIDGET (proxy));
777 gtk_container_add (GTK_CONTAINER (self->box_proxy), GTK_WIDGET (proxy));
778
779 /* Create and store a NMClient instance if it doesn't exist yet */
780 if (!cc_object_storage_has_object (CC_OBJECT_NMCLIENT)) {
781 g_autoptr(NMClient) client = nm_client_new (NULL, NULL);
782 cc_object_storage_add_object (CC_OBJECT_NMCLIENT, client);
783 }
784
785 /* use NetworkManager client */
786 self->client = cc_object_storage_get_object (CC_OBJECT_NMCLIENT);
787
788 g_signal_connect_object (self->client, "notify::nm-running" ,
789 G_CALLBACK (manager_running), self, G_CONNECT_SWAPPED);
790 g_signal_connect_object (self->client, "notify::active-connections",
791 G_CALLBACK (active_connections_changed), self, G_CONNECT_SWAPPED);
792 g_signal_connect_object (self->client, "device-added",
793 G_CALLBACK (device_added_cb), self, G_CONNECT_SWAPPED);
794 g_signal_connect_object (self->client, "device-removed",
795 G_CALLBACK (device_removed_cb), self, G_CONNECT_SWAPPED);
796
797 /* Setup ModemManager client */
798 system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
799 if (system_bus == NULL) {
800 g_warning ("Error connecting to system D-Bus: %s",
801 error->message);
802 } else {
803 self->modem_manager = mm_manager_new_sync (system_bus,
804 G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
805 NULL,
806 &error);
807 if (self->modem_manager == NULL)
808 g_warning ("Error connecting to ModemManager: %s",
809 error->message);
810 }
811
812 /* add remote settings such as VPN settings as virtual devices */
813 g_signal_connect_object (self->client, NM_CLIENT_CONNECTION_ADDED,
814 G_CALLBACK (add_connection), self, G_CONNECT_SWAPPED);
815 g_signal_connect_object (self->client, NM_CLIENT_CONNECTION_REMOVED,
816 G_CALLBACK (client_connection_removed_cb), self, G_CONNECT_SWAPPED);
817
818 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
819 g_signal_connect_after (toplevel, "map", G_CALLBACK (on_toplevel_map), self);
820
821 /* Cold-plug existing connections */
822 connections = nm_client_get_connections (self->client);
823 if (connections) {
824 for (i = 0; i < connections->len; i++)
825 add_connection (self, connections->pdata[i]);
826 }
827
828 g_debug ("Calling handle_argv() after cold-plugging connections");
829 handle_argv (self);
830 }
831