1 /*
2  * e-dbus-server.c
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 
18 /**
19  * SECTION: e-dbus-server
20  * @include: libebackend/libebackend.h
21  * @short_description: An abstract base class for a D-Bus server
22  **/
23 
24 #include "evolution-data-server-config.h"
25 
26 #include <glib.h>
27 
28 #ifdef G_OS_UNIX
29 #include <glib-unix.h>
30 #endif
31 
32 #include <libedataserver/libedataserver.h>
33 
34 #include <libebackend/e-backend-enumtypes.h>
35 
36 #include "e-dbus-server.h"
37 
38 #define INACTIVITY_TIMEOUT 10  /* seconds */
39 
40 struct _EDBusServerPrivate {
41 	GMainLoop *main_loop;
42 	guint bus_owner_id;
43 	guint hang_up_id;
44 	guint terminate_id;
45 
46 	guint inactivity_timeout_id;
47 	guint use_count;
48 	gboolean wait_for_client;
49 	EDBusServerExitCode exit_code;
50 
51 	GMutex property_lock;
52 
53 	GFileMonitor *directory_monitor;
54 };
55 
56 enum {
57 	BUS_ACQUIRED,
58 	BUS_NAME_ACQUIRED,
59 	BUS_NAME_LOST,
60 	RUN_SERVER,
61 	QUIT_SERVER,
62 	LAST_SIGNAL
63 };
64 
65 static guint signals[LAST_SIGNAL];
66 
67 static GHashTable *loaded_modules;
68 G_LOCK_DEFINE_STATIC (loaded_modules);
69 
70 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (
71 	EDBusServer, e_dbus_server, G_TYPE_OBJECT,
72 	G_ADD_PRIVATE (EDBusServer)
73 	G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))
74 
75 typedef struct _ModuleLoadData {
76 	GWeakRef server_wr;
77 	gchar *filename;
78 } ModuleLoadData;
79 
80 static ModuleLoadData *
module_load_data_new(EDBusServer * server,const gchar * filename)81 module_load_data_new (EDBusServer *server,
82 		      const gchar *filename)
83 {
84 	ModuleLoadData *mld;
85 
86 	mld = g_slice_new0 (ModuleLoadData);
87 	g_weak_ref_init (&mld->server_wr, server);
88 	mld->filename = g_strdup (filename);
89 
90 	return mld;
91 }
92 
93 static void
module_load_data_free(gpointer ptr)94 module_load_data_free (gpointer ptr)
95 {
96 	ModuleLoadData *mld = ptr;
97 
98 	if (mld) {
99 		g_weak_ref_clear (&mld->server_wr);
100 		g_free (mld->filename);
101 		g_slice_free (ModuleLoadData, mld);
102 	}
103 }
104 
105 static gboolean
e_dbus_server_load_module_timeout_cb(gpointer user_data)106 e_dbus_server_load_module_timeout_cb (gpointer user_data)
107 {
108 	ModuleLoadData *mld = user_data;
109 	EDBusServer *server;
110 
111 	g_return_val_if_fail (mld != NULL, FALSE);
112 
113 	server = g_weak_ref_get (&mld->server_wr);
114 	if (server) {
115 		EModule *module;
116 
117 		e_source_registry_debug_print ("Loading module '%s'\n", mld->filename);
118 
119 		module = e_module_load_file (mld->filename);
120 		if (module) {
121 			g_type_module_unuse ((GTypeModule *) module);
122 
123 			e_dbus_server_quit (server, E_DBUS_SERVER_EXIT_RELOAD);
124 		}
125 
126 		g_object_unref (server);
127 	}
128 
129 	return FALSE;
130 }
131 
132 static void
e_dbus_server_schedule_module_load(EDBusServer * server,const gchar * filename)133 e_dbus_server_schedule_module_load (EDBusServer *server,
134 				    const gchar *filename)
135 {
136 	g_return_if_fail (E_IS_DBUS_SERVER (server));
137 	g_return_if_fail (filename != NULL);
138 
139 	e_source_registry_debug_print ("Schedule load of module '%s'\n", filename);
140 
141 	/* Delay the load by 10 seconds, in case the module doesn't have placed
142 	   all its libraries in the expected directories. */
143 	g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, 10, e_dbus_server_load_module_timeout_cb,
144 		module_load_data_new (server, filename), module_load_data_free);
145 }
146 
147 static void
dbus_server_bus_acquired_cb(GDBusConnection * connection,const gchar * bus_name,EDBusServer * server)148 dbus_server_bus_acquired_cb (GDBusConnection *connection,
149                              const gchar *bus_name,
150                              EDBusServer *server)
151 {
152 	g_signal_emit (server, signals[BUS_ACQUIRED], 0, connection);
153 }
154 
155 static void
dbus_server_name_acquired_cb(GDBusConnection * connection,const gchar * bus_name,EDBusServer * server)156 dbus_server_name_acquired_cb (GDBusConnection *connection,
157                               const gchar *bus_name,
158                               EDBusServer *server)
159 {
160 	g_signal_emit (server, signals[BUS_NAME_ACQUIRED], 0, connection);
161 }
162 
163 static void
dbus_server_name_lost_cb(GDBusConnection * connection,const gchar * bus_name,EDBusServer * server)164 dbus_server_name_lost_cb (GDBusConnection *connection,
165                           const gchar *bus_name,
166                           EDBusServer *server)
167 {
168 	g_signal_emit (server, signals[BUS_NAME_LOST], 0, connection);
169 }
170 
171 static gboolean
dbus_server_inactivity_timeout_cb(gpointer user_data)172 dbus_server_inactivity_timeout_cb (gpointer user_data)
173 {
174 	EDBusServer *server = E_DBUS_SERVER (user_data);
175 
176 	e_dbus_server_quit (server, E_DBUS_SERVER_EXIT_NORMAL);
177 
178 	return FALSE;
179 }
180 
181 #ifdef G_OS_UNIX
182 static gboolean
dbus_server_hang_up_cb(gpointer user_data)183 dbus_server_hang_up_cb (gpointer user_data)
184 {
185 	EDBusServer *server = E_DBUS_SERVER (user_data);
186 
187 	e_source_registry_debug_print ("Received hang up signal.\n");
188 	e_dbus_server_quit (server, E_DBUS_SERVER_EXIT_RELOAD);
189 
190 	return FALSE;
191 }
192 
193 static gboolean
dbus_server_terminate_cb(gpointer user_data)194 dbus_server_terminate_cb (gpointer user_data)
195 {
196 	EDBusServer *server = E_DBUS_SERVER (user_data);
197 
198 	e_source_registry_debug_print ("Received terminate signal.\n");
199 	e_dbus_server_quit (server, E_DBUS_SERVER_EXIT_NORMAL);
200 
201 	return FALSE;
202 }
203 #endif
204 
205 static void
dbus_server_finalize(GObject * object)206 dbus_server_finalize (GObject *object)
207 {
208 	EDBusServerPrivate *priv;
209 
210 	priv = E_DBUS_SERVER (object)->priv;
211 
212 	g_main_loop_unref (priv->main_loop);
213 
214 	if (priv->bus_owner_id > 0)
215 		g_bus_unown_name (priv->bus_owner_id);
216 
217 	if (priv->hang_up_id > 0)
218 		g_source_remove (priv->hang_up_id);
219 
220 	if (priv->terminate_id > 0)
221 		g_source_remove (priv->terminate_id);
222 
223 	if (priv->inactivity_timeout_id > 0)
224 		g_source_remove (priv->inactivity_timeout_id);
225 
226 	g_mutex_clear (&priv->property_lock);
227 
228 	/* Chain up to parent's finalize() method. */
229 	G_OBJECT_CLASS (e_dbus_server_parent_class)->finalize (object);
230 }
231 
232 static void
dbus_server_dispose(GObject * object)233 dbus_server_dispose (GObject *object)
234 {
235 	EDBusServer *server = E_DBUS_SERVER (object);
236 
237 	g_clear_object (&server->priv->directory_monitor);
238 
239 	/* Chain up to parent's method. */
240 	G_OBJECT_CLASS (e_dbus_server_parent_class)->dispose (object);
241 }
242 
243 static void
dbus_server_constructed(GObject * object)244 dbus_server_constructed (GObject *object)
245 {
246 	e_dbus_server_load_modules (E_DBUS_SERVER (object));
247 
248 	e_extensible_load_extensions (E_EXTENSIBLE (object));
249 
250 	/* Chain up to parent's constructed() method. */
251 	G_OBJECT_CLASS (e_dbus_server_parent_class)->constructed (object);
252 }
253 
254 static void
dbus_server_bus_acquired(EDBusServer * server,GDBusConnection * connection)255 dbus_server_bus_acquired (EDBusServer *server,
256                           GDBusConnection *connection)
257 {
258 	if (server->priv->use_count == 0 && !server->priv->wait_for_client) {
259 		server->priv->inactivity_timeout_id =
260 			e_named_timeout_add_seconds (
261 				INACTIVITY_TIMEOUT, (GSourceFunc)
262 				dbus_server_inactivity_timeout_cb,
263 				server);
264 	}
265 }
266 
267 static void
dbus_server_bus_name_acquired(EDBusServer * server,GDBusConnection * connection)268 dbus_server_bus_name_acquired (EDBusServer *server,
269                                GDBusConnection *connection)
270 {
271 	EDBusServerClass *class;
272 
273 	class = E_DBUS_SERVER_GET_CLASS (server);
274 	g_return_if_fail (class != NULL);
275 	g_return_if_fail (class->bus_name != NULL);
276 
277 	e_source_registry_debug_print ("Bus name '%s' acquired.\n", class->bus_name);
278 }
279 
280 static void
dbus_server_bus_name_lost(EDBusServer * server,GDBusConnection * connection)281 dbus_server_bus_name_lost (EDBusServer *server,
282                            GDBusConnection *connection)
283 {
284 	EDBusServerClass *class;
285 
286 	class = E_DBUS_SERVER_GET_CLASS (server);
287 	g_return_if_fail (class != NULL);
288 	g_return_if_fail (class->bus_name != NULL);
289 
290 	e_source_registry_debug_print ("Bus name '%s' lost.\n", class->bus_name);
291 
292 	e_dbus_server_quit (server, E_DBUS_SERVER_EXIT_NORMAL);
293 }
294 
295 static EDBusServerExitCode
dbus_server_run_server(EDBusServer * server)296 dbus_server_run_server (EDBusServer *server)
297 {
298 	EDBusServerClass *class;
299 
300 	/* Try to acquire the well-known bus name. */
301 
302 	class = E_DBUS_SERVER_GET_CLASS (server);
303 	g_return_val_if_fail (class != NULL, E_DBUS_SERVER_EXIT_NONE);
304 	g_return_val_if_fail (class->bus_name != NULL, E_DBUS_SERVER_EXIT_NONE);
305 
306 	server->priv->bus_owner_id = g_bus_own_name (
307 		G_BUS_TYPE_SESSION,
308 		class->bus_name,
309 		G_BUS_NAME_OWNER_FLAGS_REPLACE |
310 		G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
311 		(GBusAcquiredCallback) dbus_server_bus_acquired_cb,
312 		(GBusNameAcquiredCallback) dbus_server_name_acquired_cb,
313 		(GBusNameLostCallback) dbus_server_name_lost_cb,
314 		g_object_ref (server),
315 		(GDestroyNotify) g_object_unref);
316 
317 	g_main_loop_run (server->priv->main_loop);
318 
319 	return server->priv->exit_code;
320 }
321 
322 static void
dbus_server_quit_server(EDBusServer * server,EDBusServerExitCode code)323 dbus_server_quit_server (EDBusServer *server,
324                          EDBusServerExitCode code)
325 {
326 	/* If we're reloading, voluntarily relinquish our bus
327 	 * name to avoid triggering a "bus-name-lost" signal. */
328 	if (code == E_DBUS_SERVER_EXIT_RELOAD) {
329 		if (server->priv->bus_owner_id) {
330 			g_bus_unown_name (server->priv->bus_owner_id);
331 			server->priv->bus_owner_id = 0;
332 		}
333 	}
334 
335 	server->priv->exit_code = code;
336 	g_main_loop_quit (server->priv->main_loop);
337 }
338 
339 static void
ignore_log(const gchar * log_domain,GLogLevelFlags log_level,const gchar * message,gpointer user_data)340 ignore_log (const gchar *log_domain,
341             GLogLevelFlags log_level,
342             const gchar *message,
343             gpointer user_data)
344 {
345 	/* Avoid printing of trivial messages while running test
346 	 * cases.  Only print warnings, criticals and errors. */
347 	if ((log_level & (G_LOG_FLAG_FATAL     |
348 			  G_LOG_LEVEL_ERROR    |
349 			  G_LOG_LEVEL_CRITICAL |
350 			  G_LOG_LEVEL_WARNING)) != 0)
351 		g_log_default_handler (log_domain, log_level, message, user_data);
352 }
353 
354 static void
e_dbus_server_class_init(EDBusServerClass * class)355 e_dbus_server_class_init (EDBusServerClass *class)
356 {
357 	GObjectClass *object_class;
358 
359 	object_class = G_OBJECT_CLASS (class);
360 	object_class->finalize = dbus_server_finalize;
361 	object_class->dispose = dbus_server_dispose;
362 	object_class->constructed = dbus_server_constructed;
363 
364 	class->bus_acquired = dbus_server_bus_acquired;
365 	class->bus_name_acquired = dbus_server_bus_name_acquired;
366 	class->bus_name_lost = dbus_server_bus_name_lost;
367 	class->run_server = dbus_server_run_server;
368 	class->quit_server = dbus_server_quit_server;
369 
370 	/**
371 	 * EDBusServer::bus-acquired:
372 	 * @server: the #EDBusServer which emitted the signal
373 	 * @connection: the #GDBusConnection to the session bus
374 	 *
375 	 * Emitted when @server acquires a connection to the session bus.
376 	 **/
377 	signals[BUS_ACQUIRED] = g_signal_new (
378 		"bus-acquired",
379 		G_OBJECT_CLASS_TYPE (object_class),
380 		G_SIGNAL_RUN_LAST,
381 		G_STRUCT_OFFSET (EDBusServerClass, bus_acquired),
382 		NULL, NULL, NULL,
383 		G_TYPE_NONE, 1,
384 		G_TYPE_DBUS_CONNECTION);
385 
386 	/**
387 	 * EDBusServer::bus-name-acquired:
388 	 * @server: the #EDBusServer which emitted the signal
389 	 * @connection: the #GDBusConnection to the session bus
390 	 *
391 	 * Emitted when @server acquires its well-known session bus name.
392 	 **/
393 	signals[BUS_NAME_ACQUIRED] = g_signal_new (
394 		"bus-name-acquired",
395 		G_OBJECT_CLASS_TYPE (object_class),
396 		G_SIGNAL_RUN_LAST,
397 		G_STRUCT_OFFSET (EDBusServerClass, bus_name_acquired),
398 		NULL, NULL, NULL,
399 		G_TYPE_NONE, 1,
400 		G_TYPE_DBUS_CONNECTION);
401 
402 	/**
403 	 * EDBusServer::bus-name-lost:
404 	 * @server: the #EDBusServer which emitted the signal
405 	 * @connection: the #GDBusconnection to the session bus,
406 	 *              or %NULL if the connection has been closed
407 	 *
408 	 * Emitted when @server loses its well-known session bus name
409 	 * or the session bus connection has been closed.
410 	 **/
411 	signals[BUS_NAME_LOST] = g_signal_new (
412 		"bus-name-lost",
413 		G_OBJECT_CLASS_TYPE (object_class),
414 		G_SIGNAL_RUN_LAST,
415 		G_STRUCT_OFFSET (EDBusServerClass, bus_name_lost),
416 		NULL, NULL, NULL,
417 		G_TYPE_NONE, 1,
418 		G_TYPE_DBUS_CONNECTION);
419 
420 	/**
421 	 * EDBusServer::run-server:
422 	 * @server: the #EDBusServer which emitted the signal
423 	 *
424 	 * Emitted to request that @server start its main loop and
425 	 * attempt to acquire its well-known session bus name.
426 	 *
427 	 * Returns: an #EDBusServerExitCode
428 	 **/
429 	signals[RUN_SERVER] = g_signal_new (
430 		"run-server",
431 		G_OBJECT_CLASS_TYPE (object_class),
432 		G_SIGNAL_RUN_LAST,
433 		G_STRUCT_OFFSET (EDBusServerClass, run_server),
434 		NULL, NULL, NULL,
435 		E_TYPE_DBUS_SERVER_EXIT_CODE, 0);
436 
437 	/**
438 	 * EDBusServer::quit-server:
439 	 * @server: the #EDBusServer which emitted the signal
440 	 * @code: an #EDBusServerExitCode
441 	 *
442 	 * Emitted to request that @server quit its main loop.
443 	 **/
444 	signals[QUIT_SERVER] = g_signal_new (
445 		"quit-server",
446 		G_OBJECT_CLASS_TYPE (object_class),
447 		G_SIGNAL_RUN_LAST,
448 		G_STRUCT_OFFSET (EDBusServerClass, quit_server),
449 		NULL, NULL, NULL,
450 		G_TYPE_NONE, 1,
451 		E_TYPE_DBUS_SERVER_EXIT_CODE);
452 
453 	if (g_getenv ("EDS_TESTING") != NULL)
454 		g_log_set_default_handler (ignore_log, NULL);
455 }
456 
457 static void
e_dbus_server_init(EDBusServer * server)458 e_dbus_server_init (EDBusServer *server)
459 {
460 #if !GLIB_CHECK_VERSION(2, 58, 0)
461 	/* Workaround glib bug https://bugzilla.gnome.org/show_bug.cgi?id=793727
462 	   Do not place this into class_init(), otherwise it can trigger
463 	   deadlock under _g_dbus_initialize () at gdbusprivate.c:1950 */
464 	g_network_monitor_get_default ();
465 #endif
466 
467 	server->priv = e_dbus_server_get_instance_private (server);
468 	server->priv->main_loop = g_main_loop_new (NULL, FALSE);
469 	server->priv->wait_for_client = FALSE;
470 
471 	g_mutex_init (&server->priv->property_lock);
472 
473 #ifdef G_OS_UNIX
474 	server->priv->hang_up_id = g_unix_signal_add (
475 		SIGHUP, dbus_server_hang_up_cb, server);
476 	server->priv->terminate_id = g_unix_signal_add (
477 		SIGTERM, dbus_server_terminate_cb, server);
478 #endif
479 }
480 
481 /**
482  * e_dbus_server_run:
483  * @server: an #EDBusServer
484  * @wait_for_client: continue running until a client connects
485  *
486  * Emits the #EDBusServer::run signal.
487  *
488  * By default the @server will start its main loop and attempt to acquire
489  * its well-known session bus name.  If the @server's main loop is already
490  * running, the function will immediately return #E_DBUS_SERVER_EXIT_NONE.
491  * Otherwise the function blocks until e_dbus_server_quit() is called.
492  *
493  * If @wait_for_client is %TRUE, the @server will continue running until
494  * the first client connection is made instead of quitting on its own if
495  * no client connection is made within the first few seconds.
496  *
497  * Returns: the exit code passed to e_dbus_server_quit()
498  *
499  * Since: 3.4
500  **/
501 EDBusServerExitCode
e_dbus_server_run(EDBusServer * server,gboolean wait_for_client)502 e_dbus_server_run (EDBusServer *server,
503                    gboolean wait_for_client)
504 {
505 	EDBusServerExitCode exit_code;
506 
507 	g_return_val_if_fail (
508 		E_IS_DBUS_SERVER (server),
509 		E_DBUS_SERVER_EXIT_NONE);
510 
511 	server->priv->wait_for_client = wait_for_client;
512 
513 	if (g_main_loop_is_running (server->priv->main_loop))
514 		return E_DBUS_SERVER_EXIT_NONE;
515 
516 	g_signal_emit (server, signals[RUN_SERVER], 0, &exit_code);
517 
518 	return exit_code;
519 }
520 
521 /**
522  * e_dbus_server_quit:
523  * @server: an #EDBusServer
524  * @code: an #EDBusServerExitCode
525  *
526  * Emits the #EDBusServer::quit signal with the given @code.
527  *
528  * By default the @server will quit its main loop and cause
529  * e_dbus_server_run() to return @code.
530  *
531  * Since: 3.4
532  **/
533 void
e_dbus_server_quit(EDBusServer * server,EDBusServerExitCode code)534 e_dbus_server_quit (EDBusServer *server,
535                     EDBusServerExitCode code)
536 {
537 	g_return_if_fail (E_IS_DBUS_SERVER (server));
538 
539 	g_signal_emit (server, signals[QUIT_SERVER], 0, code);
540 }
541 
542 /**
543  * e_dbus_server_hold:
544  * @server: an #EDBusServer
545  *
546  * Increases the use count of @server.
547  *
548  * Use this function to indicate that the server has a reason to continue
549  * to run.  To cancel the hold, call e_dbus_server_release().
550  *
551  * Since: 3.4
552  **/
553 void
e_dbus_server_hold(EDBusServer * server)554 e_dbus_server_hold (EDBusServer *server)
555 {
556 	g_return_if_fail (E_IS_DBUS_SERVER (server));
557 
558 	g_mutex_lock (&server->priv->property_lock);
559 
560 	if (server->priv->inactivity_timeout_id > 0) {
561 		g_source_remove (server->priv->inactivity_timeout_id);
562 		server->priv->inactivity_timeout_id = 0;
563 	}
564 
565 	server->priv->use_count++;
566 
567 	g_mutex_unlock (&server->priv->property_lock);
568 }
569 
570 /**
571  * e_dbus_server_release:
572  * @server: an #EDBusServer
573  *
574  * Decreates the use count of @server.
575  *
576  * When the use count reaches zero, the server will stop running.
577  *
578  * Never call this function except to cancel the effect of a previous call
579  * to e_dbus_server_hold().
580  *
581  * Since: 3.4
582  **/
583 void
e_dbus_server_release(EDBusServer * server)584 e_dbus_server_release (EDBusServer *server)
585 {
586 	g_return_if_fail (E_IS_DBUS_SERVER (server));
587 	g_return_if_fail (server->priv->use_count > 0);
588 
589 	g_mutex_lock (&server->priv->property_lock);
590 
591 	server->priv->use_count--;
592 
593 	if (server->priv->use_count == 0) {
594 		server->priv->inactivity_timeout_id =
595 			e_named_timeout_add_seconds (
596 				INACTIVITY_TIMEOUT, (GSourceFunc)
597 				dbus_server_inactivity_timeout_cb,
598 				server);
599 	}
600 
601 	g_mutex_unlock (&server->priv->property_lock);
602 }
603 
604 static void
dbus_server_module_directory_changed_cb(GFileMonitor * monitor,GFile * file,GFile * other_file,GFileMonitorEvent event_type,gpointer user_data)605 dbus_server_module_directory_changed_cb (GFileMonitor *monitor,
606 					 GFile *file,
607 					 GFile *other_file,
608 					 GFileMonitorEvent event_type,
609 					 gpointer user_data)
610 {
611 	EDBusServer *server;
612 
613 	g_return_if_fail (E_IS_DBUS_SERVER (user_data));
614 
615 	server = E_DBUS_SERVER (user_data);
616 
617 	if (event_type == G_FILE_MONITOR_EVENT_CREATED ||
618 	    event_type == G_FILE_MONITOR_EVENT_DELETED ||
619 	    event_type == G_FILE_MONITOR_EVENT_MOVED_IN ||
620 	    event_type == G_FILE_MONITOR_EVENT_MOVED_OUT ||
621 	    event_type == G_FILE_MONITOR_EVENT_RENAMED) {
622 		gchar *filename;
623 
624 		filename = g_file_get_path (file);
625 
626 		if (event_type == G_FILE_MONITOR_EVENT_RENAMED && other_file) {
627 			G_LOCK (loaded_modules);
628 			if (!g_hash_table_contains (loaded_modules, filename)) {
629 				gchar *other_filename = g_file_get_path (other_file);
630 				e_source_registry_debug_print ("Module file '%s' renamed to '%s'\n", filename, other_filename);
631 				g_free (filename);
632 				filename = other_filename;
633 				event_type = G_FILE_MONITOR_EVENT_CREATED;
634 			}
635 			G_UNLOCK (loaded_modules);
636 		}
637 
638 		if (filename && g_str_has_suffix (filename, "." G_MODULE_SUFFIX)) {
639 			if (event_type == G_FILE_MONITOR_EVENT_CREATED ||
640 			    event_type == G_FILE_MONITOR_EVENT_MOVED_IN) {
641 				G_LOCK (loaded_modules);
642 
643 				if (!g_hash_table_contains (loaded_modules, filename)) {
644 					g_hash_table_add (loaded_modules, g_strdup (filename));
645 					e_dbus_server_schedule_module_load (server, filename);
646 				}
647 
648 				G_UNLOCK (loaded_modules);
649 			}
650 		}
651 
652 		g_free (filename);
653 	}
654 }
655 
656 /**
657  * e_dbus_server_load_modules:
658  * @server: an #EDBusServer
659  *
660  * This function should be called once during @server initialization to
661  * load all available library modules to extend the @server's functionality.
662  *
663  * Since: 3.4
664  **/
665 void
e_dbus_server_load_modules(EDBusServer * server)666 e_dbus_server_load_modules (EDBusServer *server)
667 {
668 	EDBusServerClass *class;
669 	gboolean already_loaded;
670 	GList *list, *link;
671 
672 	g_return_if_fail (E_IS_DBUS_SERVER (server));
673 
674 	class = E_DBUS_SERVER_GET_CLASS (server);
675 	g_return_if_fail (class != NULL);
676 	g_return_if_fail (class->module_directory != NULL);
677 
678 	/* This ensures a module directory is only loaded once. */
679 	G_LOCK (loaded_modules);
680 	if (loaded_modules == NULL)
681 		loaded_modules = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
682 	already_loaded = g_hash_table_contains (loaded_modules, class->module_directory);
683 	if (!already_loaded)
684 		g_hash_table_add (loaded_modules, g_strdup (class->module_directory));
685 	G_UNLOCK (loaded_modules);
686 
687 	if (!server->priv->directory_monitor) {
688 		GFile *dir_file;
689 
690 		dir_file = g_file_new_for_path (class->module_directory);
691 		server->priv->directory_monitor = g_file_monitor_directory (dir_file, G_FILE_MONITOR_WATCH_MOVES, NULL, NULL);
692 		g_clear_object (&dir_file);
693 
694 		if (server->priv->directory_monitor) {
695 			g_signal_connect (server->priv->directory_monitor, "changed",
696 				G_CALLBACK (dbus_server_module_directory_changed_cb), server);
697 		}
698 	}
699 
700 	if (already_loaded)
701 		return;
702 
703 	G_LOCK (loaded_modules);
704 
705 	list = e_module_load_all_in_directory_and_prefixes (class->module_directory, E_DATA_SERVER_PREFIX);
706 	for (link = list; link; link = g_list_next (link)) {
707 		EModule *module = link->data;
708 
709 		if (!module || !e_module_get_filename (module))
710 			continue;
711 
712 		g_hash_table_add (loaded_modules, g_strdup (e_module_get_filename (module)));
713 	}
714 
715 	G_UNLOCK (loaded_modules);
716 
717 	g_list_free_full (list, (GDestroyNotify) g_type_module_unuse);
718 }
719