GNetworkMonitor *network_monitor;
gulong network_changed_handler_id;
+ guint network_changed_timeout_id;
GMutex network_monitor_cancellable_lock;
GCancellable *network_monitor_cancellable;
g_slice_free (AsyncContext, async_context);
}
+struct UpdateOnlineData
+{
+ EBackend *backend;
+ gboolean is_online;
+};
+
+static gpointer
+set_backend_online_thread (gpointer user_data)
+{
+ struct UpdateOnlineData *uod = user_data;
+
+ g_return_val_if_fail (uod != NULL, NULL);
+
+ e_backend_set_online (uod->backend, uod->is_online);
+
+ g_object_unref (uod->backend);
+ g_slice_free (struct UpdateOnlineData, uod);
+
+ return NULL;
+}
+
static void
backend_network_monitor_can_reach_cb (GObject *source_object,
GAsyncResult *result,
{
EBackend *backend = E_BACKEND (user_data);
gboolean host_is_reachable;
+ struct UpdateOnlineData *uod;
+ GThread *thread;
GError *error = NULL;
host_is_reachable = g_network_monitor_can_reach_finish (
(host_is_reachable && (error == NULL)) ||
(!host_is_reachable && (error != NULL)));
- if (host_is_reachable) {
- e_backend_set_online (backend, TRUE);
-
- } else if (G_IS_IO_ERROR (error, G_IO_ERROR_CANCELLED)) {
- /* Ignore cancellations. */
-
- } else if (G_IS_IO_ERROR (error, G_IO_ERROR_HOST_UNREACHABLE)) {
- e_backend_set_online (backend, FALSE);
-
- } else if (G_IS_RESOLVER_ERROR (error, G_RESOLVER_ERROR_NOT_FOUND)) {
- e_backend_set_online (backend, FALSE);
-
- } else {
- g_warning ("%s: %s", G_STRFUNC, error->message);
+ if (G_IS_IO_ERROR (error, G_IO_ERROR_CANCELLED) ||
+ (host_is_reachable ? 1 : 0) == (e_backend_get_online (backend) ? 1 : 0)) {
+ g_clear_error (&error);
+ g_object_unref (backend);
+ return;
}
- if (error != NULL)
- g_error_free (error);
+ g_clear_error (&error);
+
+ uod = g_slice_new (struct UpdateOnlineData);
+ uod->backend = backend;
+ uod->is_online = host_is_reachable;
- g_object_unref (backend);
+ /* do this in a separate thread, not the main thread */
+ thread = g_thread_new (NULL, set_backend_online_thread, uod);
+ g_thread_unref (thread);
}
static void
cancellable = NULL;
}
+ if (connectable && G_IS_NETWORK_ADDRESS (connectable)) {
+ GNetworkAddress *network_address = G_NETWORK_ADDRESS (connectable);
+
+ /* create copy of the backend's connectable, because once the connectable
+ reaches its destination it caches the value and doesn't retry after
+ network changes.
+
+ This should be eventually replaced with default implementation
+ of EBackend::get_destination_address() doing basically the same
+ what currently does the backend silently on construction, thus
+ it'll get also current values from the ESource, not stale from
+ construct time.
+ */
+ connectable = g_network_address_new (
+ g_network_address_get_hostname (network_address),
+ g_network_address_get_port (network_address));
+
+ g_object_unref (network_address);
+ }
+
+ if (!connectable) {
+ gchar *host = NULL;
+ guint16 port = 0;
+
+ if (e_backend_get_destination_address (backend, &host, &port) && host)
+ connectable = g_network_address_new (host, port);
+
+ g_free (host);
+ }
+
if (connectable == NULL) {
e_backend_set_online (backend, TRUE);
} else {
g_object_unref (connectable);
}
+static gboolean
+backend_network_changed_timeout_cb (gpointer user_data)
+{
+ EBackend *backend = user_data;
+
+ if (!g_source_is_destroyed (g_main_current_source ())) {
+ backend->priv->network_changed_timeout_id = 0;
+
+ backend_update_online_state (backend);
+ }
+
+ return FALSE;
+}
+
static void
backend_network_changed_cb (GNetworkMonitor *network_monitor,
gboolean network_available,
EBackend *backend)
{
- backend_update_online_state (backend);
+ if (backend->priv->network_changed_timeout_id)
+ g_source_remove (backend->priv->network_changed_timeout_id);
+
+ /* wait few seconds, a network change can fire this event multiple times */
+ backend->priv->network_changed_timeout_id = g_timeout_add_seconds (3, backend_network_changed_timeout_cb, backend);
}
static void
priv->network_changed_handler_id = 0;
}
+ if (priv->network_changed_timeout_id) {
+ g_source_remove (priv->network_changed_timeout_id);
+ priv->network_changed_timeout_id = 0;
+ }
+
g_clear_object (&priv->source);
g_clear_object (&priv->prompter);
g_clear_object (&priv->connectable);
g_mutex_clear (&priv->property_lock);
g_mutex_clear (&priv->network_monitor_cancellable_lock);
+ if (priv->network_changed_timeout_id) {
+ g_source_remove (priv->network_changed_timeout_id);
+ priv->network_changed_timeout_id = 0;
+ }
+
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_backend_parent_class)->finalize (object);
}
GNetworkMonitor *network_monitor;
GSocketConnectable *connectable;
- network_monitor = g_network_monitor_get_default ();
+ network_monitor = backend->priv->network_monitor;
connectable = g_network_address_new (host, port);
if (connectable) {