1 /*
2  * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
3  *
4  * This library is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include "evolution-data-server-config.h"
18 
19 #include <gio/gio.h>
20 
21 #include "e-network-monitor.h"
22 
23 struct _ENetworkMonitorPrivate {
24 	GMutex property_lock;
25 	gchar *gio_name;
26 	GNetworkMonitor *gio_monitor;
27 	gulong network_available_notify_id;
28 	gulong network_metered_notify_id;
29 	gulong network_connectivity_notify_id;
30 	gulong network_changed_id;
31 	GSource *network_changed_source;
32 };
33 
34 enum {
35 	PROP_0,
36 	PROP_GIO_NAME,
37 	PROP_CONNECTIVITY,
38 	PROP_NETWORK_METERED,
39 	PROP_NETWORK_AVAILABLE
40 };
41 
42 static guint network_changed_signal = 0;
43 
44 static void e_network_monitor_initable_iface_init (GInitableIface *iface);
45 static void e_network_monitor_gio_iface_init (GNetworkMonitorInterface *iface);
46 
G_DEFINE_TYPE_WITH_CODE(ENetworkMonitor,e_network_monitor,G_TYPE_OBJECT,G_ADD_PRIVATE (ENetworkMonitor)G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,e_network_monitor_initable_iface_init)G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR,e_network_monitor_gio_iface_init))47 G_DEFINE_TYPE_WITH_CODE (ENetworkMonitor, e_network_monitor, G_TYPE_OBJECT,
48 	G_ADD_PRIVATE (ENetworkMonitor)
49 	G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, e_network_monitor_initable_iface_init)
50 	G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR, e_network_monitor_gio_iface_init))
51 
52 static GNetworkConnectivity
53 e_network_monitor_get_connectivity (ENetworkMonitor *network_monitor)
54 {
55 	GNetworkConnectivity connectivity;
56 
57 	g_return_val_if_fail (E_IS_NETWORK_MONITOR (network_monitor), G_NETWORK_CONNECTIVITY_LOCAL);
58 
59 	g_mutex_lock (&network_monitor->priv->property_lock);
60 
61 	if (network_monitor->priv->gio_monitor)
62 		connectivity = g_network_monitor_get_connectivity (network_monitor->priv->gio_monitor);
63 	else
64 		connectivity = G_NETWORK_CONNECTIVITY_FULL;
65 
66 	g_mutex_unlock (&network_monitor->priv->property_lock);
67 
68 	return connectivity;
69 }
70 
71 static gboolean
e_network_monitor_get_network_available(ENetworkMonitor * network_monitor)72 e_network_monitor_get_network_available (ENetworkMonitor *network_monitor)
73 {
74 	gboolean network_available;
75 
76 	g_return_val_if_fail (E_IS_NETWORK_MONITOR (network_monitor), FALSE);
77 
78 	g_mutex_lock (&network_monitor->priv->property_lock);
79 
80 	if (network_monitor->priv->gio_monitor)
81 		network_available = g_network_monitor_get_network_available (network_monitor->priv->gio_monitor);
82 	else
83 		network_available = TRUE;
84 
85 	g_mutex_unlock (&network_monitor->priv->property_lock);
86 
87 	return network_available;
88 }
89 
90 static gboolean
e_network_monitor_get_network_metered(ENetworkMonitor * network_monitor)91 e_network_monitor_get_network_metered (ENetworkMonitor *network_monitor)
92 {
93 	gboolean network_metered;
94 
95 	g_return_val_if_fail (E_IS_NETWORK_MONITOR (network_monitor), FALSE);
96 
97 	g_mutex_lock (&network_monitor->priv->property_lock);
98 
99 	if (network_monitor->priv->gio_monitor)
100 		network_metered = g_network_monitor_get_network_metered (network_monitor->priv->gio_monitor);
101 	else
102 		network_metered = FALSE;
103 
104 	g_mutex_unlock (&network_monitor->priv->property_lock);
105 
106 	return network_metered;
107 }
108 
109 static gboolean
e_network_monitor_emit_network_changed_idle_cb(gpointer user_data)110 e_network_monitor_emit_network_changed_idle_cb (gpointer user_data)
111 {
112 	ENetworkMonitor *network_monitor = user_data;
113 	gboolean is_available;
114 
115 	g_return_val_if_fail (E_IS_NETWORK_MONITOR (network_monitor), FALSE);
116 
117 	g_object_ref (network_monitor);
118 
119 	is_available = e_network_monitor_get_network_available (network_monitor);
120 	g_signal_emit (network_monitor, network_changed_signal, 0, is_available);
121 
122 	g_source_unref (network_monitor->priv->network_changed_source);
123 	network_monitor->priv->network_changed_source = NULL;
124 
125 	g_object_unref (network_monitor);
126 
127 	return FALSE;
128 }
129 
130 static void
e_network_monitor_schedule_network_changed_emit(ENetworkMonitor * network_monitor)131 e_network_monitor_schedule_network_changed_emit (ENetworkMonitor *network_monitor)
132 {
133 	g_mutex_lock (&network_monitor->priv->property_lock);
134 
135 	if (!network_monitor->priv->network_changed_source) {
136 		network_monitor->priv->network_changed_source = g_idle_source_new ();
137 		/* Use G_PRIORITY_HIGH_IDLE priority so that multiple
138 		 * network-change-related notifications coming in at
139 		 * G_PRIORITY_DEFAULT will get coalesced into one signal
140 		 * emission.
141 		 */
142 		g_source_set_priority (network_monitor->priv->network_changed_source, G_PRIORITY_HIGH_IDLE);
143 		g_source_set_callback (network_monitor->priv->network_changed_source,
144 			e_network_monitor_emit_network_changed_idle_cb, network_monitor, NULL);
145 		g_source_attach (network_monitor->priv->network_changed_source, NULL);
146 	}
147 
148 	g_mutex_unlock (&network_monitor->priv->property_lock);
149 }
150 
151 static void
e_network_monitor_notify_cb(GNetworkMonitor * gio_monitor,GParamSpec * param,ENetworkMonitor * network_monitor)152 e_network_monitor_notify_cb (GNetworkMonitor *gio_monitor,
153 			     GParamSpec *param,
154 			     ENetworkMonitor *network_monitor)
155 {
156 	g_return_if_fail (G_IS_NETWORK_MONITOR (gio_monitor));
157 	g_return_if_fail (param && param->name);
158 	g_return_if_fail (E_IS_NETWORK_MONITOR (network_monitor));
159 
160 	g_object_notify (G_OBJECT (network_monitor), param->name);
161 }
162 
163 static void
e_network_monitor_network_changed_cb(GNetworkMonitor * gio_monitor,gboolean is_available,ENetworkMonitor * network_monitor)164 e_network_monitor_network_changed_cb (GNetworkMonitor *gio_monitor,
165 				      gboolean is_available,
166 				      ENetworkMonitor *network_monitor)
167 {
168 	g_return_if_fail (G_IS_NETWORK_MONITOR (gio_monitor));
169 	g_return_if_fail (E_IS_NETWORK_MONITOR (network_monitor));
170 
171 	e_network_monitor_schedule_network_changed_emit (network_monitor);
172 }
173 
174 static void
e_network_monitor_disconnect_gio_monitor_locked(ENetworkMonitor * network_monitor)175 e_network_monitor_disconnect_gio_monitor_locked (ENetworkMonitor *network_monitor)
176 {
177 	if (!network_monitor->priv->gio_monitor)
178 		return;
179 
180 	#define disconnect_signal(x) G_STMT_START { \
181 		if (network_monitor->priv->x) { \
182 			g_signal_handler_disconnect (network_monitor->priv->gio_monitor, network_monitor->priv->x); \
183 			network_monitor->priv->x = 0; \
184 		} \
185 		} G_STMT_END
186 
187 	disconnect_signal (network_available_notify_id);
188 	disconnect_signal (network_metered_notify_id);
189 	disconnect_signal (network_connectivity_notify_id);
190 	disconnect_signal (network_changed_id);
191 
192 	#undef disconnect_signal
193 }
194 
195 static void
e_network_monitor_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)196 e_network_monitor_set_property (GObject *object,
197 				guint property_id,
198 				const GValue *value,
199 				GParamSpec *pspec)
200 {
201 	switch (property_id) {
202 		case PROP_GIO_NAME:
203 			e_network_monitor_set_gio_name (
204 				E_NETWORK_MONITOR (object),
205 				g_value_get_string (value));
206 			return;
207 	}
208 
209 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
210 }
211 
212 static void
e_network_monitor_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)213 e_network_monitor_get_property (GObject *object,
214 				guint property_id,
215 				GValue *value,
216 				GParamSpec *pspec)
217 {
218 	switch (property_id) {
219 		case PROP_GIO_NAME:
220 			g_value_take_string (
221 				value,
222 				e_network_monitor_dup_gio_name (
223 				E_NETWORK_MONITOR (object)));
224 			return;
225 
226 		case PROP_CONNECTIVITY:
227 			g_value_set_enum (
228 				value,
229 				e_network_monitor_get_connectivity (
230 				E_NETWORK_MONITOR (object)));
231 			return;
232 
233 		case PROP_NETWORK_METERED:
234 			g_value_set_boolean (
235 				value,
236 				e_network_monitor_get_network_metered (
237 				E_NETWORK_MONITOR (object)));
238 			return;
239 
240 		case PROP_NETWORK_AVAILABLE:
241 			g_value_set_boolean (
242 				value,
243 				e_network_monitor_get_network_available (
244 				E_NETWORK_MONITOR (object)));
245 			return;
246 	}
247 
248 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
249 }
250 
251 static void
e_network_monitor_constructed(GObject * object)252 e_network_monitor_constructed (GObject *object)
253 {
254 	GSettings *settings;
255 
256 	/* Chain up to parent's method. */
257 	G_OBJECT_CLASS (e_network_monitor_parent_class)->constructed (object);
258 
259 	settings = g_settings_new ("org.gnome.evolution-data-server");
260 	g_settings_bind (
261 		settings, "network-monitor-gio-name",
262 		object, "gio-name",
263 		G_SETTINGS_BIND_DEFAULT);
264 	g_object_unref (settings);
265 }
266 
267 static void
e_network_monitor_finalize(GObject * object)268 e_network_monitor_finalize (GObject *object)
269 {
270 	ENetworkMonitor *network_monitor = E_NETWORK_MONITOR (object);
271 
272 	if (network_monitor->priv->network_changed_source) {
273 		g_source_destroy (network_monitor->priv->network_changed_source);
274 		g_source_unref (network_monitor->priv->network_changed_source);
275 		network_monitor->priv->network_changed_source = NULL;
276 	}
277 
278 	g_mutex_lock (&network_monitor->priv->property_lock);
279 	e_network_monitor_disconnect_gio_monitor_locked (network_monitor);
280 	g_mutex_unlock (&network_monitor->priv->property_lock);
281 
282 	g_mutex_clear (&network_monitor->priv->property_lock);
283 	g_clear_object (&network_monitor->priv->gio_monitor);
284 	g_free (network_monitor->priv->gio_name);
285 
286 	/* Chain up to parent's method. */
287 	G_OBJECT_CLASS (e_network_monitor_parent_class)->finalize (object);
288 }
289 
290 static void
e_network_monitor_class_init(ENetworkMonitorClass * class)291 e_network_monitor_class_init (ENetworkMonitorClass *class)
292 {
293 	GObjectClass *object_class;
294 
295 	object_class = G_OBJECT_CLASS (class);
296 	object_class->set_property = e_network_monitor_set_property;
297 	object_class->get_property = e_network_monitor_get_property;
298 	object_class->constructed = e_network_monitor_constructed;
299 	object_class->finalize = e_network_monitor_finalize;
300 
301 	/**
302 	 * ENetworkMonitor:gio-name:
303 	 *
304 	 * The GIO name of the underlying #GNetworkMonitor to use.
305 	 **/
306 	g_object_class_install_property (
307 		object_class,
308 		PROP_GIO_NAME,
309 		g_param_spec_string (
310 			"gio-name",
311 			"GIO name",
312 			NULL,
313 			NULL,
314 			G_PARAM_READWRITE |
315 			G_PARAM_EXPLICIT_NOTIFY |
316 			G_PARAM_STATIC_STRINGS));
317 
318 	g_object_class_override_property (object_class, PROP_NETWORK_AVAILABLE, "network-available");
319 	g_object_class_override_property (object_class, PROP_NETWORK_METERED, "network-metered");
320 	g_object_class_override_property (object_class, PROP_CONNECTIVITY, "connectivity");
321 }
322 
323 static void
e_network_monitor_init(ENetworkMonitor * network_monitor)324 e_network_monitor_init (ENetworkMonitor *network_monitor)
325 {
326 	network_monitor->priv = e_network_monitor_get_instance_private (network_monitor);
327 
328 	g_mutex_init (&network_monitor->priv->property_lock);
329 }
330 
331 static gboolean
e_network_monitor_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)332 e_network_monitor_initable_init (GInitable *initable,
333 				 GCancellable *cancellable,
334 				 GError **error)
335 {
336 	return TRUE;
337 }
338 
339 static void
e_network_monitor_initable_iface_init(GInitableIface * iface)340 e_network_monitor_initable_iface_init (GInitableIface *iface)
341 {
342 	iface->init = e_network_monitor_initable_init;
343 }
344 
345 static gboolean
e_network_monitor_can_reach(GNetworkMonitor * monitor,GSocketConnectable * connectable,GCancellable * cancellable,GError ** error)346 e_network_monitor_can_reach (GNetworkMonitor *monitor,
347 			     GSocketConnectable *connectable,
348 			     GCancellable *cancellable,
349 			     GError **error)
350 {
351 	ENetworkMonitor *network_monitor;
352 	GNetworkMonitor *use_gio_monitor = NULL;
353 	gboolean can_reach;
354 
355 	g_return_val_if_fail (E_IS_NETWORK_MONITOR (monitor), FALSE);
356 
357 	network_monitor = E_NETWORK_MONITOR (monitor);
358 
359 	g_mutex_lock (&network_monitor->priv->property_lock);
360 
361 	if (network_monitor->priv->gio_monitor)
362 		use_gio_monitor = g_object_ref (network_monitor->priv->gio_monitor);
363 
364 	g_mutex_unlock (&network_monitor->priv->property_lock);
365 
366 	if (use_gio_monitor)
367 		can_reach = g_network_monitor_can_reach (use_gio_monitor, connectable, cancellable, error);
368 	else
369 		can_reach = TRUE;
370 
371 	g_clear_object (&use_gio_monitor);
372 
373 	return can_reach;
374 }
375 
376 static void
e_network_monitor_can_reach_async_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)377 e_network_monitor_can_reach_async_thread (GTask *task,
378 					  gpointer source_object,
379 					  gpointer task_data,
380 					  GCancellable *cancellable)
381 {
382 	gboolean success;
383 	GError *local_error = NULL;
384 
385 	success = e_network_monitor_can_reach (source_object, task_data, cancellable, &local_error);
386 
387 	if (local_error)
388 		g_task_return_error (task, local_error);
389 	else
390 		g_task_return_boolean (task, success);
391 }
392 
393 static void
e_network_monitor_can_reach_async(GNetworkMonitor * monitor,GSocketConnectable * connectable,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)394 e_network_monitor_can_reach_async (GNetworkMonitor *monitor,
395 				   GSocketConnectable *connectable,
396 				   GCancellable *cancellable,
397 				   GAsyncReadyCallback callback,
398 				   gpointer user_data)
399 {
400 	GTask *task;
401 
402 	g_return_if_fail (E_IS_NETWORK_MONITOR (monitor));
403 	g_return_if_fail (G_IS_SOCKET_CONNECTABLE (connectable));
404 
405 	task = g_task_new (monitor, cancellable, callback, user_data);
406 	g_task_set_source_tag (task, e_network_monitor_can_reach_async);
407 	g_task_set_task_data (task, g_object_ref (connectable), g_object_unref);
408 
409 	g_task_run_in_thread (task, e_network_monitor_can_reach_async_thread);
410 
411 	g_object_unref (task);
412 }
413 
414 static gboolean
e_network_monitor_can_reach_finish(GNetworkMonitor * monitor,GAsyncResult * result,GError ** error)415 e_network_monitor_can_reach_finish (GNetworkMonitor *monitor,
416 				    GAsyncResult *result,
417 				    GError **error)
418 {
419 	g_return_val_if_fail (E_IS_NETWORK_MONITOR (monitor), FALSE);
420 	g_return_val_if_fail (g_task_is_valid (result, monitor), FALSE);
421 
422 	g_return_val_if_fail (
423 		g_async_result_is_tagged (
424 		result, e_network_monitor_can_reach_async), FALSE);
425 
426 	return g_task_propagate_boolean (G_TASK (result), error);
427 }
428 
429 static void
e_network_monitor_gio_iface_init(GNetworkMonitorInterface * iface)430 e_network_monitor_gio_iface_init (GNetworkMonitorInterface *iface)
431 {
432 	iface->can_reach = e_network_monitor_can_reach;
433 	iface->can_reach_async = e_network_monitor_can_reach_async;
434 	iface->can_reach_finish = e_network_monitor_can_reach_finish;
435 
436 	if (!network_changed_signal)
437 		network_changed_signal = g_signal_lookup ("network-changed", G_TYPE_NETWORK_MONITOR);
438 }
439 
440 static GNetworkMonitor *
e_network_monitor_create_instance_for_gio_name(const gchar * gio_name)441 e_network_monitor_create_instance_for_gio_name (const gchar *gio_name)
442 {
443 	GIOExtensionPoint *pnt;
444 	GList *extensions, *link;
445 
446 	if (!gio_name || !*gio_name)
447 		return NULL;
448 
449 	/* To initialize the GIO extension point for the GNetworkMonitor */
450 	g_network_monitor_get_default ();
451 
452 	pnt = g_io_extension_point_lookup (G_NETWORK_MONITOR_EXTENSION_POINT_NAME);
453 	if (!pnt)
454 		return NULL;
455 
456 	extensions = g_io_extension_point_get_extensions (pnt);
457 
458 	for (link = extensions; link; link = g_list_next (link)) {
459 		GIOExtension *ext = link->data;
460 
461 		if (g_strcmp0 (g_io_extension_get_name (ext), gio_name) == 0)
462 			return g_initable_new (g_io_extension_get_type (ext), NULL, NULL, NULL);
463 	}
464 
465 	return NULL;
466 }
467 
468 /**
469  * e_network_monitor_get_default:
470  *
471  * Gets the default #ENetworkMonitor. The caller should not unref the returned instance.
472  * The #ENetworkMonitor implements the #GNetworkMonitor iterface.
473  *
474  * Returns: (transfer none): The default #ENetworkMonitor instance.
475  *
476  * Since: 3.22
477  **/
478 GNetworkMonitor *
e_network_monitor_get_default(void)479 e_network_monitor_get_default (void)
480 {
481 	static GNetworkMonitor *network_monitor = NULL;
482 	G_LOCK_DEFINE_STATIC (network_monitor);
483 
484 	G_LOCK (network_monitor);
485 	if (!network_monitor)
486 		network_monitor = g_initable_new (E_TYPE_NETWORK_MONITOR, NULL, NULL, NULL);
487 	G_UNLOCK (network_monitor);
488 
489 	return network_monitor;
490 }
491 
492 /**
493  * e_network_monitor_list_gio_names:
494  * @network_monitor: an #ENetworkMonitor
495  *
496  * Get a list of available GIO names for the #GNetworkMonitor implementations.
497  * The strings can be used in e_network_monitor_set_gio_name().
498  *
499  * Returns: (transfer full) (element-type utf8): A newly allocated #GSList,
500  *   with newly allocated strings, the GIO names. The #GSList should be freed
501  *   with g_slist_free_full (gio_names, g_free); when no longer needed.
502  *
503  * Since: 3.22
504  **/
505 GSList *
e_network_monitor_list_gio_names(ENetworkMonitor * network_monitor)506 e_network_monitor_list_gio_names (ENetworkMonitor *network_monitor)
507 {
508 	GIOExtensionPoint *pnt;
509 	GList *extensions, *link;
510 	GSList *gio_names = NULL;
511 
512 	g_return_val_if_fail (E_IS_NETWORK_MONITOR (network_monitor), NULL);
513 
514 	/* To initialize the GIO extension point for the GNetworkMonitor */
515 	g_network_monitor_get_default ();
516 
517 	pnt = g_io_extension_point_lookup (G_NETWORK_MONITOR_EXTENSION_POINT_NAME);
518 	if (!pnt)
519 		return NULL;
520 
521 	extensions = g_io_extension_point_get_extensions (pnt);
522 
523 	for (link = extensions; link; link = g_list_next (link)) {
524 		GIOExtension *ext = link->data;
525 
526 		gio_names = g_slist_prepend (gio_names, g_strdup (g_io_extension_get_name (ext)));
527 	}
528 
529 	return g_slist_reverse (gio_names);
530 }
531 
532 /**
533  * e_network_monitor_dup_gio_name:
534  * @network_monitor: an #ENetworkMonitor
535  *
536  * Get currently set GIO name for the network availability checks.
537  * See e_network_monitor_set_gio_name() for more details.
538  *
539  * Returns: (transfer full): A newly allocated string, a GIO name
540  *   of the underlying GNetworkMonitor which is set to be used.
541  *   The returned string should be freed with g_free(), when
542  *   no longer needed.
543  *
544  * Since: 3.22
545  **/
546 gchar *
e_network_monitor_dup_gio_name(ENetworkMonitor * network_monitor)547 e_network_monitor_dup_gio_name (ENetworkMonitor *network_monitor)
548 {
549 	gchar *gio_name;
550 
551 	g_return_val_if_fail (E_IS_NETWORK_MONITOR (network_monitor), NULL);
552 
553 	g_mutex_lock (&network_monitor->priv->property_lock);
554 	gio_name = g_strdup (network_monitor->priv->gio_name);
555 	g_mutex_unlock (&network_monitor->priv->property_lock);
556 
557 	return gio_name;
558 }
559 
560 /**
561  * e_network_monitor_set_gio_name:
562  * @network_monitor: an #ENetworkMonitor
563  * @gio_name: (nullable): a GIO name of a #GNetworkMonitor implementation to use, or %NULL
564  *
565  * Set a @gio_name of the #GNetworkMonitor implementation to use, can be %NULL.
566  * Use e_network_monitor_list_gio_names() for a list of available
567  * implementations. A special value, %E_NETWORK_MONITOR_ALWAYS_ONLINE_NAME, can
568  * be used to report the network as always reachable. When an unknown GIO
569  * name is used the default #GNetworkMonitor implementation, as returned
570  * by the g_network_monitor_get_default(), will be used.
571  *
572  * Since: 3.22
573  **/
574 void
e_network_monitor_set_gio_name(ENetworkMonitor * network_monitor,const gchar * gio_name)575 e_network_monitor_set_gio_name (ENetworkMonitor *network_monitor,
576 				const gchar *gio_name)
577 {
578 	GObject *object;
579 
580 	g_return_if_fail (E_IS_NETWORK_MONITOR (network_monitor));
581 
582 	g_mutex_lock (&network_monitor->priv->property_lock);
583 
584 	if (g_strcmp0 (gio_name, network_monitor->priv->gio_name) == 0) {
585 		g_mutex_unlock (&network_monitor->priv->property_lock);
586 		return;
587 	}
588 
589 	g_free (network_monitor->priv->gio_name);
590 	network_monitor->priv->gio_name = g_strdup (gio_name);
591 
592 	if (network_monitor->priv->gio_monitor)
593 		e_network_monitor_disconnect_gio_monitor_locked (network_monitor);
594 
595 	g_clear_object (&network_monitor->priv->gio_monitor);
596 
597 	if (g_strcmp0 (network_monitor->priv->gio_name, E_NETWORK_MONITOR_ALWAYS_ONLINE_NAME) != 0) {
598 		GNetworkMonitor *gio_monitor;
599 
600 		gio_monitor = e_network_monitor_create_instance_for_gio_name (network_monitor->priv->gio_name);
601 		if (!gio_monitor)
602 			gio_monitor = g_object_ref (g_network_monitor_get_default ());
603 
604 		network_monitor->priv->gio_monitor = gio_monitor;
605 
606 		if (gio_monitor) {
607 			network_monitor->priv->network_available_notify_id =
608 				g_signal_connect (network_monitor->priv->gio_monitor, "notify::network-available",
609 					G_CALLBACK (e_network_monitor_notify_cb), network_monitor);
610 
611 			network_monitor->priv->network_metered_notify_id =
612 				g_signal_connect (network_monitor->priv->gio_monitor, "notify::network-metered",
613 					G_CALLBACK (e_network_monitor_notify_cb), network_monitor);
614 
615 			network_monitor->priv->network_connectivity_notify_id =
616 				g_signal_connect (network_monitor->priv->gio_monitor, "notify::connectivity",
617 					G_CALLBACK (e_network_monitor_notify_cb), network_monitor);
618 
619 			network_monitor->priv->network_changed_id =
620 				g_signal_connect (network_monitor->priv->gio_monitor, "network-changed",
621 					G_CALLBACK (e_network_monitor_network_changed_cb), network_monitor);
622 		}
623 	}
624 
625 	g_mutex_unlock (&network_monitor->priv->property_lock);
626 
627 	object = G_OBJECT (network_monitor);
628 
629 	g_object_freeze_notify (object);
630 	g_object_notify (object, "gio-name");
631 	g_object_notify (object, "network-available");
632 	g_object_notify (object, "network-metered");
633 	g_object_notify (object, "connectivity");
634 	g_object_thaw_notify (object);
635 
636 	e_network_monitor_schedule_network_changed_emit (network_monitor);
637 }
638