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