3ff24cac9b827db0ecdf13ac61443533c2a6ad3c
[platform/upstream/ibus.git] / bus / dbusimpl.c
1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /* vim:set et sts=4: */
3 /* ibus - The Input Bus
4  * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
5  * Copyright (C) 2008-2010 Red Hat, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library 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 GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "dbusimpl.h"
24
25 #include <string.h>
26
27 #include "global.h"
28 #include "ibusimpl.h"
29 #include "marshalers.h"
30 #include "matchrule.h"
31 #include "registry.h"
32 #include "types.h"
33
34 enum {
35     NAME_OWNER_CHANGED,
36     NAME_LOST,
37     NAME_ACQUIRED,
38     LAST_SIGNAL,
39 };
40
41 enum {
42     PROP_0,
43 };
44
45 static guint dbus_signals[LAST_SIGNAL] = { 0 };
46
47 struct _BusDBusImpl {
48     IBusService parent;
49
50     /* instance members */
51     /* a map from a unique bus name (e.g. ":1.0") to a BusConnection. */
52     GHashTable *unique_names;
53     /* a map from a requested well-known name (e.g. "org.freedesktop.IBus.Panel") to a BusNameService. */
54     GHashTable *names;
55     /* a list of IBusService objects. */
56     GList *objects;
57     /* a list of active BusConnections. */
58     GList *connections;
59     /* a list of BusMatchRules requested by the connections above. */
60     GList *rules;
61     /* a serial number used to generate a unique name of a bus. */
62     guint id;
63
64     GMutex *dispatch_lock;
65     GList *dispatch_queue;
66
67     GMutex *forward_lock;
68     GList *forward_queue;
69
70     /* a list of BusMethodCall to be used to reply when services are
71        really available */
72     GList *start_service_calls;
73 };
74
75 struct _BusDBusImplClass {
76     IBusServiceClass parent;
77
78     /* class members */
79     void    (* name_owner_changed) (BusDBusImpl     *dbus,
80                                     BusConnection   *connection,
81                                     gchar           *name,
82                                     gchar           *old_name,
83                                     gchar           *new_name);
84
85     void    (* name_lost)          (BusDBusImpl     *dbus,
86                                     BusConnection   *connection,
87                                     gchar           *name);
88
89     void    (* name_acquired)      (BusDBusImpl     *dbus,
90                                     BusConnection   *connection,
91                                     gchar           *name);
92 };
93
94 typedef struct _BusDispatchData BusDispatchData;
95 struct _BusDispatchData {
96     GDBusMessage *message;
97     BusConnection *skip_connection;
98 };
99
100 typedef struct _BusNameService BusNameService;
101 struct _BusNameService {
102     gchar *name;
103     GSList *owners;
104 };
105
106 typedef struct _BusConnectionOwner BusConnectionOwner;
107 struct _BusConnectionOwner {
108     BusConnection *conn;
109
110     guint allow_replacement : 1;
111     guint do_not_queue : 1;
112 };
113
114 typedef struct _BusMethodCall BusMethodCall;
115 struct _BusMethodCall {
116     BusDBusImpl *dbus;
117     BusConnection *connection;
118     GVariant *parameters;
119     GDBusMethodInvocation *invocation;
120     guint timeout_id;
121 };
122
123 /* functions prototype */
124 static void     bus_dbus_impl_destroy           (BusDBusImpl        *dbus);
125 static void     bus_dbus_impl_service_method_call
126                                                 (IBusService        *service,
127                                                  GDBusConnection    *dbus_connection,
128                                                  const gchar        *sender,
129                                                  const gchar        *object_path,
130                                                  const gchar        *interface_name,
131                                                  const gchar        *method_name,
132                                                  GVariant           *parameters,
133                                                  GDBusMethodInvocation
134                                                                     *invocation);
135 static GVariant *bus_dbus_impl_service_get_property
136                                                 (IBusService        *service,
137                                                  GDBusConnection    *connection,
138                                                  const gchar        *sender,
139                                                  const gchar        *object_path,
140                                                  const gchar        *interface_name,
141                                                  const gchar        *property_name,
142                                                  GError            **error);
143 static gboolean  bus_dbus_impl_service_set_property
144                                                 (IBusService        *service,
145                                                  GDBusConnection    *connection,
146                                                  const gchar        *sender,
147                                                  const gchar        *object_path,
148                                                  const gchar        *interface_name,
149                                                  const gchar        *property_name,
150                                                  GVariant           *value,
151                                                  GError            **error);
152 static void      bus_dbus_impl_name_owner_changed
153                                                 (BusDBusImpl        *dbus,
154                                                  BusConnection      *connection,
155                                                  gchar              *name,
156                                                  gchar              *old_name,
157                                                  gchar              *new_name);
158 static void      bus_dbus_impl_name_lost
159                                                 (BusDBusImpl        *dbus,
160                                                  BusConnection      *connection,
161                                                  gchar              *name);
162 static void      bus_dbus_impl_name_acquired
163                                                 (BusDBusImpl        *dbus,
164                                                  BusConnection      *connection,
165                                                  gchar              *name);
166 static void      bus_dbus_impl_connection_destroy_cb
167                                                 (BusConnection      *connection,
168                                                  BusDBusImpl        *dbus);
169 static void      bus_dbus_impl_rule_destroy_cb  (BusMatchRule       *rule,
170                                                  BusDBusImpl        *dbus);
171 static void      bus_dbus_impl_object_destroy_cb(IBusService        *object,
172                                                  BusDBusImpl        *dbus);
173
174 G_DEFINE_TYPE(BusDBusImpl, bus_dbus_impl, IBUS_TYPE_SERVICE)
175
176 /* The D-Bus interfaces available in this class, which consists of a list of methods this class implements and
177  * a list of signals this class may emit. See bus_dbus_impl_new_connection and ibusservice.c for more details. */
178 static const gchar introspection_xml[] =
179     "<node>"
180     "  <interface name='org.freedesktop.DBus'>"
181     "    <method name='Hello'>"
182     "      <arg direction='out' type='s' name='unique_name' />"
183     "    </method>"
184     "    <method name='RequestName'>"
185     "      <arg direction='in'  type='s' name='name' />"
186     "      <arg direction='in'  type='u' name='flags' />"
187     "      <arg direction='out' type='u' />"
188     "    </method>"
189     "    <method name='ReleaseName'>"
190     "      <arg direction='in'  type='s' name='name' />"
191     "      <arg direction='out' type='u' />"
192     "    </method>"
193     "    <method name='StartServiceByName'>"
194     "      <arg direction='in'  type='s' />"
195     "      <arg direction='in'  type='u' />"
196     "      <arg direction='out' type='u' />"
197     "    </method>"
198     "    <method name='UpdateActivationEnvironment'>"
199     "      <arg direction='in' type='a{ss}'/>"
200     "    </method>"
201     "    <method name='NameHasOwner'>"
202     "      <arg direction='in'  type='s' name='name' />"
203     "      <arg direction='out' type='b' />"
204     "    </method>"
205     "    <method name='ListNames'>"
206     "      <arg direction='out' type='as' />"
207     "    </method>"
208     "    <method name='ListActivatableNames'>"
209     "      <arg direction='out' type='as' />"
210     "    </method>"
211     "    <method name='AddMatch'>"
212     "      <arg direction='in'  type='s' name='match_rule' />"
213     "    </method>"
214     "    <method name='RemoveMatch'>"
215     "      <arg direction='in'  type='s' name='match_rule' />"
216     "    </method>"
217     "    <method name='GetNameOwner'>"
218     "      <arg direction='in'  type='s' name='name' />"
219     "      <arg direction='out' type='s' name='unique_name' />"
220     "    </method>"
221     "    <method name='ListQueuedOwners'>"
222     "      <arg direction='in'  type='s' name='name' />"
223     "      <arg direction='out' type='as' />"
224     "    </method>"
225     "    <method name='GetConnectionUnixUser'>"
226     "      <arg direction='in'  type='s' />"
227     "      <arg direction='out' type='u' />"
228     "    </method>"
229     "    <method name='GetConnectionUnixProcessID'>"
230     "      <arg direction='in'  type='s' />"
231     "      <arg direction='out' type='u' />"
232     "    </method>"
233     "    <method name='GetAdtAuditSessionData'>"
234     "      <arg direction='in'  type='s' />"
235     "      <arg direction='out' type='ay' />"
236     "    </method>"
237     "    <method name='GetConnectionSELinuxSecurityContext'>"
238     "      <arg direction='in'  type='s' />"
239     "      <arg direction='out' type='ay' />"
240     "    </method>"
241     "    <method name='ReloadConfig' />"
242     "    <method name='GetId'>"
243     "      <arg direction='out' type='s' />"
244     "    </method>"
245     "    <signal name='NameOwnerChanged'>"
246     "      <arg type='s' name='name' />"
247     "      <arg type='s' name='old_owner' />"
248     "      <arg type='s' name='new_owner' />"
249     "    </signal>"
250     "    <signal name='NameLost'>"
251     "      <arg type='s' name='name' />"
252     "    </signal>"
253     "    <signal name='NameAcquired'>"
254     "      <arg type='s' name='name' />"
255     "    </signal>"
256     "  </interface>"
257     "</node>";
258
259 static void
260 bus_connection_owner_set_flags (BusConnectionOwner *owner,
261                                 guint32             flags)
262 {
263     owner->allow_replacement =
264         (flags & IBUS_BUS_NAME_FLAG_ALLOW_REPLACEMENT) != 0;
265
266     owner->do_not_queue =
267         (flags & IBUS_BUS_NAME_FLAG_DO_NOT_QUEUE) != 0;
268 }
269
270 static BusConnectionOwner *
271 bus_connection_owner_new (BusConnection *connection,
272                           guint32        flags)
273 {
274     BusConnectionOwner *owner = NULL;
275
276     g_assert (BUS_IS_CONNECTION (connection));
277
278     owner = g_slice_new (BusConnectionOwner);
279     if (owner != NULL) {
280         owner->conn = g_object_ref (connection);
281         bus_connection_owner_set_flags (owner, flags);
282     }
283
284     return owner;
285 }
286
287 static void
288 bus_connection_owner_free (BusConnectionOwner *owner)
289 {
290     g_assert (owner != NULL);
291
292     g_object_unref (owner->conn);
293     owner->conn = NULL;
294     g_slice_free (BusConnectionOwner, owner);
295 }
296
297 static GSList *
298 bus_name_service_find_owner_link (BusNameService *service,
299                                    BusConnection  *connection)
300 {
301     GSList *owners = service->owners;
302
303     while (owners) {
304         BusConnectionOwner *owner = (BusConnectionOwner *) owners->data;
305         if (owner->conn == connection) {
306             break;
307         }
308         owners = owners->next;
309     }
310
311     return owners;
312 }
313
314 static BusNameService *
315 bus_name_service_new (const gchar *name)
316 {
317     BusNameService *service = NULL;
318
319     g_assert (name != NULL);
320
321     service = g_slice_new (BusNameService);
322     g_assert (service != NULL);
323
324     service->name = g_strdup (name);
325     service->owners = NULL;
326
327     return service;
328 }
329
330 static void
331 bus_name_service_free (BusNameService *service)
332 {
333     GSList *list = NULL;
334
335     g_assert (service != NULL);
336
337     g_slist_free_full (service->owners,
338                        (GDestroyNotify) bus_connection_owner_free);
339     service->owners = NULL;
340
341     g_free (service->name);
342     g_slice_free (BusNameService, service);
343 }
344
345 static void
346 bus_name_service_set_primary_owner (BusNameService     *service,
347                                     BusConnectionOwner *owner,
348                                     BusDBusImpl        *dbus)
349 {
350     g_assert (service != NULL);
351     g_assert (owner != NULL);
352     g_assert (dbus != NULL);
353
354     BusConnectionOwner *old = service->owners != NULL ?
355             (BusConnectionOwner *)service->owners->data : NULL;
356
357     if (old != NULL) {
358         g_signal_emit (dbus,
359                        dbus_signals[NAME_LOST],
360                        0,
361                        old->conn,
362                        service->name);
363     }
364
365     g_signal_emit (dbus,
366                    dbus_signals[NAME_ACQUIRED],
367                    0,
368                    owner->conn,
369                    service->name ? service->name : "");
370
371     g_signal_emit (dbus,
372                    dbus_signals[NAME_OWNER_CHANGED],
373                    0,
374                    owner->conn,
375                    service->name,
376                    old != NULL ? bus_connection_get_unique_name (old->conn) : "",
377                    bus_connection_get_unique_name (owner->conn));
378
379     if (old != NULL && old->do_not_queue != 0) {
380         /* If old primary owner does not want to be in queue, we remove it. */
381         service->owners = g_slist_remove (service->owners, old);
382         bus_connection_remove_name (old->conn, service->name);
383         bus_connection_owner_free (old);
384     }
385
386     service->owners = g_slist_prepend (service->owners, (gpointer) owner);
387 }
388
389 static BusConnectionOwner *
390 bus_name_service_get_primary_owner (BusNameService *service)
391 {
392     g_assert (service != NULL);
393
394     if (service->owners == NULL) {
395         return NULL;
396     }
397
398     return (BusConnectionOwner *) service->owners->data;
399 }
400
401 static void
402 bus_name_service_add_non_primary_owner (BusNameService     *service,
403                                         BusConnectionOwner *owner,
404                                         BusDBusImpl        *dbus)
405 {
406     g_assert (service != NULL);
407     g_assert (owner != NULL);
408     g_assert (dbus != NULL);
409     g_assert (service->owners != NULL);
410
411     service->owners = g_slist_append (service->owners, (gpointer) owner);
412 }
413
414 static BusConnectionOwner *
415 bus_name_service_find_owner (BusNameService *service,
416                              BusConnection  *connection)
417 {
418     g_assert (service != NULL);
419     g_assert (connection != NULL);
420
421     GSList *owners = bus_name_service_find_owner_link (service, connection);
422     if (owners != NULL)
423         return (BusConnectionOwner *)owners->data;
424     return NULL;
425 }
426
427 static void
428 bus_name_service_remove_owner (BusNameService     *service,
429                                BusConnectionOwner *owner,
430                                BusDBusImpl        *dbus)
431 {
432     GSList *owners;
433
434     g_assert (service != NULL);
435     g_assert (owner != NULL);
436
437
438     owners = bus_name_service_find_owner_link (service, owner->conn);
439     g_assert (owners != NULL);
440
441     if (owners->data == bus_name_service_get_primary_owner (service)) {
442         BusConnectionOwner *_new = NULL;
443         if (owners->next != NULL) {
444             _new = (BusConnectionOwner *)owners->next->data;
445         }
446
447         if (dbus != NULL) {
448             g_signal_emit (dbus,
449                            dbus_signals[NAME_LOST],
450                            0,
451                            owner->conn,
452                            service->name);
453             if (_new != NULL) {
454                 g_signal_emit (dbus,
455                                dbus_signals[NAME_ACQUIRED],
456                                0,
457                                _new->conn,
458                                service->name);
459             }
460             g_signal_emit (dbus,
461                     dbus_signals[NAME_OWNER_CHANGED],
462                     0,
463                     _new != NULL ? _new->conn : NULL,
464                     service->name,
465                     bus_connection_get_unique_name (owner->conn),
466                     _new != NULL ? bus_connection_get_unique_name (_new->conn) : "");
467
468         }
469     }
470
471     service->owners = g_slist_remove_link (service->owners, (gpointer) owners);
472 }
473
474 static gboolean
475 bus_name_service_get_allow_replacement (BusNameService *service)
476 {
477     BusConnectionOwner *owner = NULL;
478
479     g_assert (service != NULL);
480
481     owner = bus_name_service_get_primary_owner (service);
482     if (owner == NULL) {
483         return TRUE;
484     }
485     return owner->allow_replacement;
486 }
487
488 static BusMethodCall *
489 bus_method_call_new (BusDBusImpl           *dbus,
490                      BusConnection         *connection,
491                      GVariant              *parameters,
492                      GDBusMethodInvocation *invocation)
493 {
494     BusMethodCall *call = g_slice_new0 (BusMethodCall);
495     call->dbus = g_object_ref (dbus);
496     call->connection = g_object_ref (connection);
497     call->parameters = g_variant_ref (parameters);
498     call->invocation = g_object_ref (invocation);
499     return call;
500 }
501
502 static void
503 bus_method_call_free (BusMethodCall *call)
504 {
505     if (call->timeout_id != 0) {
506         g_source_remove (call->timeout_id);
507     }
508
509     g_object_unref (call->dbus);
510     g_object_unref (call->connection);
511     g_variant_unref (call->parameters);
512     g_object_unref (call->invocation);
513     g_slice_free (BusMethodCall, call);
514 }
515
516 static void
517 bus_dbus_impl_class_init (BusDBusImplClass *class)
518 {
519     GObjectClass *gobject_class = G_OBJECT_CLASS (class);
520
521     IBUS_OBJECT_CLASS (gobject_class)->destroy = (IBusObjectDestroyFunc) bus_dbus_impl_destroy;
522
523     /* override the default implementations in the parent class. */
524     IBUS_SERVICE_CLASS (class)->service_method_call =  bus_dbus_impl_service_method_call;
525     IBUS_SERVICE_CLASS (class)->service_get_property = bus_dbus_impl_service_get_property;
526     IBUS_SERVICE_CLASS (class)->service_set_property = bus_dbus_impl_service_set_property;
527
528     ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
529
530     /* register a handler of the name-owner-changed signal below. */
531     class->name_owner_changed = bus_dbus_impl_name_owner_changed;
532
533     /* register a handler of the name-lost signal below. */
534     class->name_lost = bus_dbus_impl_name_lost;
535
536     /* register a handler of the name-acquired signal below. */
537     class->name_acquired = bus_dbus_impl_name_acquired;
538
539     /* install signals */
540     dbus_signals[NAME_OWNER_CHANGED] =
541         g_signal_new (I_("name-owner-changed"),
542             G_TYPE_FROM_CLASS (class),
543             G_SIGNAL_RUN_FIRST,
544             G_STRUCT_OFFSET (BusDBusImplClass, name_owner_changed),
545             NULL, NULL,
546             bus_marshal_VOID__OBJECT_STRING_STRING_STRING,
547             G_TYPE_NONE,
548             4,
549             BUS_TYPE_CONNECTION,
550             G_TYPE_STRING,
551             G_TYPE_STRING,
552             G_TYPE_STRING);
553
554     dbus_signals[NAME_LOST] =
555         g_signal_new (I_("name-lost"),
556             G_TYPE_FROM_CLASS (class),
557             G_SIGNAL_RUN_FIRST,
558             G_STRUCT_OFFSET (BusDBusImplClass, name_lost),
559             NULL, NULL,
560             bus_marshal_VOID__OBJECT_STRING,
561             G_TYPE_NONE,
562             2,
563             BUS_TYPE_CONNECTION,
564             G_TYPE_STRING);
565
566     dbus_signals[NAME_ACQUIRED] =
567         g_signal_new (I_("name-acquired"),
568             G_TYPE_FROM_CLASS (class),
569             G_SIGNAL_RUN_FIRST,
570             G_STRUCT_OFFSET (BusDBusImplClass, name_acquired),
571             NULL, NULL,
572             bus_marshal_VOID__OBJECT_STRING,
573             G_TYPE_NONE,
574             2,
575             BUS_TYPE_CONNECTION,
576             G_TYPE_STRING);
577 }
578
579 static void
580 bus_dbus_impl_init (BusDBusImpl *dbus)
581 {
582     dbus->unique_names = g_hash_table_new (g_str_hash, g_str_equal);
583     dbus->names = g_hash_table_new_full (g_str_hash, g_str_equal,
584                                          NULL,
585                                          (GDestroyNotify) bus_name_service_free);
586
587     dbus->dispatch_lock = g_mutex_new ();
588     dbus->forward_lock = g_mutex_new ();
589
590     /* other members are automatically zero-initialized. */
591 }
592
593 static void
594 bus_dbus_impl_destroy (BusDBusImpl *dbus)
595 {
596     GList *p;
597
598     for (p = dbus->objects; p != NULL; p = p->next) {
599         IBusService *object = (IBusService *) p->data;
600         g_signal_handlers_disconnect_by_func (object,
601                 G_CALLBACK (bus_dbus_impl_object_destroy_cb), dbus);
602         ibus_object_destroy ((IBusObject *) object);
603         g_object_unref (object);
604     }
605     g_list_free (dbus->objects);
606     dbus->objects = NULL;
607
608     for (p = dbus->rules; p != NULL; p = p->next) {
609         BusMatchRule *rule = BUS_MATCH_RULE (p->data);
610         g_signal_handlers_disconnect_by_func (rule,
611                         G_CALLBACK (bus_dbus_impl_rule_destroy_cb), dbus);
612         ibus_object_destroy ((IBusObject *) rule);
613         g_object_unref (rule);
614     }
615     g_list_free (dbus->rules);
616     dbus->rules = NULL;
617
618     for (p = dbus->connections; p != NULL; p = p->next) {
619         BusConnection *connection = BUS_CONNECTION (p->data);
620         g_signal_handlers_disconnect_by_func (connection,
621                 bus_dbus_impl_connection_destroy_cb, dbus);
622         ibus_object_destroy (IBUS_OBJECT (connection));
623         g_object_unref (connection);
624     }
625     g_list_free (dbus->connections);
626     dbus->connections = NULL;
627
628     g_hash_table_remove_all (dbus->unique_names);
629     g_hash_table_remove_all (dbus->names);
630
631     dbus->unique_names = NULL;
632     dbus->names = NULL;
633
634     g_list_free_full (dbus->start_service_calls,
635                       (GDestroyNotify) bus_method_call_free);
636     dbus->start_service_calls = NULL;
637
638     /* FIXME destruct _lock and _queue members. */
639     IBUS_OBJECT_CLASS(bus_dbus_impl_parent_class)->destroy ((IBusObject *) dbus);
640 }
641
642 /**
643  * bus_dbus_impl_hello:
644  *
645  * Implement the "Hello" method call of the org.freedesktop.DBus interface.
646  * Assign a unique bus name like ":1.0" for the connection and return the name (as a D-Bus reply.)
647  */
648 static void
649 bus_dbus_impl_hello (BusDBusImpl           *dbus,
650                      BusConnection         *connection,
651                      GVariant              *parameters,
652                      GDBusMethodInvocation *invocation)
653 {
654     if (bus_connection_get_unique_name (connection) != NULL) {
655         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
656                         "Already handled an Hello message");
657     }
658     else {
659         gchar *name = g_strdup_printf (":1.%u", ++dbus->id);
660         bus_connection_set_unique_name (connection, name);
661         g_free (name);
662
663         name = (gchar *) bus_connection_get_unique_name (connection);
664         g_hash_table_insert (dbus->unique_names, name, connection);
665         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", name));
666
667         g_signal_emit (dbus,
668                        dbus_signals[NAME_OWNER_CHANGED],
669                        0,
670                        connection,
671                        name,
672                        "",
673                        name);
674     }
675 }
676
677 /**
678  * bus_dbus_impl_list_names:
679  *
680  * Implement the "ListNames" method call of the org.freedesktop.DBus interface.
681  * Return all bus names (e.g. ":1.0", "org.freedesktop.IBus.Panel") as a D-Bus reply.
682  */
683 static void
684 bus_dbus_impl_list_names (BusDBusImpl           *dbus,
685                           BusConnection         *connection,
686                           GVariant              *parameters,
687                           GDBusMethodInvocation *invocation)
688 {
689     GVariantBuilder builder;
690     g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
691
692     /* FIXME should add them? */
693     g_variant_builder_add (&builder, "s", "org.freedesktop.DBus");
694     g_variant_builder_add (&builder, "s", "org.freedesktop.IBus");
695
696     /* append well-known names */
697     GList *names, *name;
698     names = g_hash_table_get_keys (dbus->names);
699     for (name = names; name != NULL; name = name->next) {
700         g_variant_builder_add (&builder, "s", name->data);
701     }
702     g_list_free (names);
703
704     /* append unique names */
705     names = g_hash_table_get_keys (dbus->unique_names);
706     for (name = names; name != NULL; name = name->next) {
707         g_variant_builder_add (&builder, "s", name->data);
708     }
709     g_list_free (names);
710
711     g_dbus_method_invocation_return_value (invocation,
712                     g_variant_new ("(as)", &builder));
713 }
714
715 /**
716  * bus_dbus_impl_list_names:
717  *
718  * Implement the "NameHasOwner" method call of the org.freedesktop.DBus interface.
719  * Return TRUE (as a D-Bus reply) if the name is available in dbus->unique_names or is a well-known name.
720  */
721 static void
722 bus_dbus_impl_name_has_owner (BusDBusImpl           *dbus,
723                               BusConnection         *connection,
724                               GVariant              *parameters,
725                               GDBusMethodInvocation *invocation)
726 {
727     const gchar *name = NULL;
728     g_variant_get (parameters, "(&s)", &name);
729
730     gboolean has_owner;
731     if (!g_dbus_is_name (name)) {
732         g_dbus_method_invocation_return_error (invocation,
733                                                G_DBUS_ERROR,
734                                                G_DBUS_ERROR_FAILED,
735                                                "'%s' is not a legal bus name");
736         return;
737     }
738
739     if (g_dbus_is_unique_name (name)) {
740         has_owner = g_hash_table_lookup (dbus->unique_names, name) != NULL;
741     }
742     else {
743         if (g_strcmp0 (name, "org.freedesktop.DBus") == 0 ||
744             g_strcmp0 (name, "org.freedesktop.IBus") == 0)
745             has_owner = TRUE;
746         else
747             has_owner = g_hash_table_lookup (dbus->names, name) != NULL;
748     }
749     g_dbus_method_invocation_return_value (invocation,
750                     g_variant_new ("(b)", has_owner));
751 }
752
753 /**
754  * bus_dbus_impl_get_name_owner:
755  *
756  * Implement the "GetNameOwner" method call of the org.freedesktop.DBus interface.
757  */
758 static void
759 bus_dbus_impl_get_name_owner (BusDBusImpl           *dbus,
760                               BusConnection         *connection,
761                               GVariant              *parameters,
762                               GDBusMethodInvocation *invocation)
763 {
764     const gchar *name_owner = NULL;
765     const gchar *name = NULL;
766     g_variant_get (parameters, "(&s)", &name);
767
768     if (g_strcmp0 (name, "org.freedesktop.DBus") == 0 ||
769         g_strcmp0 (name, "org.freedesktop.IBus") == 0) {
770         name_owner = name;
771     }
772     else {
773         BusConnection *owner = bus_dbus_impl_get_connection_by_name (dbus, name);
774         if (owner != NULL) {
775             name_owner = bus_connection_get_unique_name (owner);
776         }
777     }
778
779     if (name_owner == NULL) {
780         g_dbus_method_invocation_return_error (invocation,
781                         G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
782                         "Can not get name owner of '%s': no such name", name);
783     }
784     else {
785         g_dbus_method_invocation_return_value (invocation,
786                         g_variant_new ("(s)", name_owner));
787     }
788 }
789
790 /**
791  * bus_dbus_impl_list_queued_owners:
792  *
793  * Implement the "ListQueuedOwners" method call of the org.freedesktop.DBus interface.
794  */
795 static void
796 bus_dbus_impl_list_queued_owners (BusDBusImpl           *dbus,
797                                   BusConnection         *connection,
798                                   GVariant              *parameters,
799                                   GDBusMethodInvocation *invocation)
800 {
801     const gchar *name = NULL;
802     const gchar *name_owner = NULL;
803     GVariantBuilder builder;
804     BusConnection *named_conn = NULL;
805
806     g_variant_get (parameters, "(&s)", &name);
807
808     g_assert (BUS_IS_DBUS_IMPL (dbus));
809     g_assert (name != NULL);
810
811     g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
812
813     if (G_LIKELY (g_dbus_is_unique_name (name))) {
814         named_conn = (BusConnection *) g_hash_table_lookup (dbus->unique_names, name);
815         if (named_conn == NULL) {
816             g_dbus_method_invocation_return_value (invocation,
817                     g_variant_new ("(as)", &builder));
818             return;
819         }
820         name_owner = bus_connection_get_unique_name (named_conn);
821         if (name_owner == NULL) {
822             g_dbus_method_invocation_return_error (invocation,
823                             G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
824                             "Can not get name owner of '%s': no such name", name);
825             return;
826         }
827         g_variant_builder_add (&builder, "s", name_owner);
828     }
829     else {
830         BusNameService *service;
831         GSList *owners;
832
833         service = (BusNameService *) g_hash_table_lookup (dbus->names, name);
834         if (service == NULL) {
835             g_dbus_method_invocation_return_value (invocation,
836                     g_variant_new ("(as)", &builder));
837             return;
838         }
839         for (owners = service->owners; owners; owners = owners->next) {
840             BusConnectionOwner *owner = (BusConnectionOwner *) owners->data;
841             if (owner == NULL) {
842                 continue;
843             }
844             named_conn = owner->conn;
845             if (named_conn == NULL) {
846                 continue;
847             }
848             name_owner = bus_connection_get_unique_name (named_conn);
849             if (name_owner == NULL) {
850                 g_dbus_method_invocation_return_error (invocation,
851                             G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
852                             "Can not get name owner of '%s': no such name", name);
853                 return;
854             }
855             g_variant_builder_add (&builder, "s", name_owner);
856         }
857     }
858
859     g_dbus_method_invocation_return_value (invocation,
860                     g_variant_new ("(as)", &builder));
861 }
862
863 /**
864  * bus_dbus_impl_get_id:
865  *
866  * Implement the "GetId" method call of the org.freedesktop.DBus interface.
867  * This function is not implemented yet and always returns a dummy string - "FIXME".
868  */
869 static void
870 bus_dbus_impl_get_id (BusDBusImpl           *dbus,
871                       BusConnection         *connection,
872                       GVariant              *parameters,
873                       GDBusMethodInvocation *invocation)
874 {
875     /* FIXME */
876     const gchar *uuid = "FIXME";
877     g_dbus_method_invocation_return_value (invocation,
878                     g_variant_new ("(s)", uuid));
879 }
880
881 /**
882  * bus_dbus_impl_rule_destroy_cb:
883  *
884  * A function to be called when one of the dbus->rules is destroyed.
885  */
886 static void
887 bus_dbus_impl_rule_destroy_cb (BusMatchRule *rule,
888                                BusDBusImpl  *dbus)
889 {
890     dbus->rules = g_list_remove (dbus->rules, rule);
891     g_object_unref (rule);
892 }
893
894 /**
895  * bus_dbus_impl_get_id:
896  *
897  * Implement the "AddMatch" method call of the org.freedesktop.DBus interface.
898  */
899 static void
900 bus_dbus_impl_add_match (BusDBusImpl           *dbus,
901                          BusConnection         *connection,
902                          GVariant              *parameters,
903                          GDBusMethodInvocation *invocation)
904 {
905     const gchar *rule_text = NULL;
906     g_variant_get (parameters, "(&s)", &rule_text);
907
908     BusMatchRule *rule = bus_match_rule_new (rule_text);
909     if (rule == NULL) {
910         g_dbus_method_invocation_return_error (invocation,
911                         G_DBUS_ERROR, G_DBUS_ERROR_MATCH_RULE_INVALID,
912                         "Parse match rule [%s] failed", rule_text);
913         return;
914     }
915
916     g_dbus_method_invocation_return_value (invocation, NULL);
917     GList *p;
918     for (p = dbus->rules; p != NULL; p = p->next) {
919         if (bus_match_rule_is_equal (rule, (BusMatchRule *) p->data)) {
920             /* The same rule is already registered. Just reuse it. */
921             bus_match_rule_add_recipient ((BusMatchRule *) p->data, connection);
922             g_object_unref (rule);
923             return;
924         }
925     }
926
927     if (rule) {
928         bus_match_rule_add_recipient (rule, connection);
929         dbus->rules = g_list_append (dbus->rules, rule);
930         g_signal_connect (rule, "destroy", G_CALLBACK (bus_dbus_impl_rule_destroy_cb), dbus);
931     }
932 }
933
934 /**
935  * bus_dbus_impl_get_id:
936  *
937  * Implement the "RemoveMatch" method call of the org.freedesktop.DBus interface.
938  */
939 static void
940 bus_dbus_impl_remove_match (BusDBusImpl           *dbus,
941                             BusConnection         *connection,
942                             GVariant              *parameters,
943                             GDBusMethodInvocation *invocation)
944 {
945     const gchar *rule_text = NULL;
946     g_variant_get (parameters, "(&s)", &rule_text);
947
948     BusMatchRule *rule = bus_match_rule_new (rule_text);
949     if (rule == NULL) {
950         g_dbus_method_invocation_return_error (invocation,
951                         G_DBUS_ERROR, G_DBUS_ERROR_MATCH_RULE_INVALID,
952                         "Parse match rule [%s] failed", rule_text);
953         return;
954     }
955
956     g_dbus_method_invocation_return_value (invocation, NULL);
957     GList *p;
958     for (p = dbus->rules; p != NULL; p = p->next) {
959         if (bus_match_rule_is_equal (rule, (BusMatchRule *) p->data)) {
960             /* p->data will be destroyed when the final recipient is removed.  */
961             bus_match_rule_remove_recipient ((BusMatchRule *) p->data, connection);
962             break;
963         }
964         /* FIXME should we return G_DBUS_ERROR if rule is not found in dbus->rules */
965     }
966     g_object_unref (rule);
967 }
968
969 /**
970  * bus_dbus_impl_request_name:
971  *
972  * Implement the "RequestName" method call of the org.freedesktop.DBus interface.
973  */
974 static void
975 bus_dbus_impl_request_name (BusDBusImpl           *dbus,
976                             BusConnection         *connection,
977                             GVariant              *parameters,
978                             GDBusMethodInvocation *invocation)
979 {
980     const gchar *name = NULL;  // e.g. "org.freedesktop.IBus.Panel"
981     guint32 flags = 0;
982     BusNameService *service = NULL;
983     BusConnectionOwner *primary_owner = NULL;
984     BusConnectionOwner *owner = NULL;
985
986     g_variant_get (parameters, "(&su)", &name, &flags);
987
988     if (name == NULL ||
989         !g_dbus_is_name (name) ||
990         g_dbus_is_unique_name (name)) {
991         g_dbus_method_invocation_return_error (invocation,
992                         G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
993                         "'%s' is not a legal service name.", name);
994         return;
995     }
996
997     if (g_strcmp0 (name, "org.freedesktop.DBus") == 0 ||
998         g_strcmp0 (name, "org.freedesktop.IBus") == 0) {
999         g_dbus_method_invocation_return_error (invocation,
1000                         G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1001                         "Can not acquire the service name '%s', it is reserved by IBus", name);
1002         return;
1003     }
1004
1005     enum {
1006         ACTION_INVALID,
1007         ACTION_IN_QUEUE,
1008         ACTION_REPLACE,
1009         ACTION_EXISTS,
1010         ACTION_ALREADY_OWN,
1011     } action = ACTION_INVALID;
1012
1013     service = (BusNameService *) g_hash_table_lookup (dbus->names, name);
1014
1015     /* If the name servise does not exist, we will create one. */
1016     if (service == NULL) {
1017         service = bus_name_service_new (name);
1018         g_hash_table_insert (dbus->names,
1019                              service->name,
1020                              service);
1021     }
1022     else {
1023         primary_owner = bus_name_service_get_primary_owner (service);
1024     }
1025
1026     if (primary_owner != NULL) {
1027         if (primary_owner->conn == connection) {
1028             action = ACTION_ALREADY_OWN;
1029         }
1030         else {
1031             action = (flags & IBUS_BUS_NAME_FLAG_DO_NOT_QUEUE) ?
1032                     ACTION_EXISTS : ACTION_IN_QUEUE;
1033             if ((bus_name_service_get_allow_replacement (service) == TRUE) &&
1034                 (flags & IBUS_BUS_NAME_FLAG_REPLACE_EXISTING)) {
1035                 action = ACTION_REPLACE;
1036             }
1037         }
1038     }
1039     else {
1040         action = ACTION_REPLACE;
1041     }
1042
1043     if (action == ACTION_ALREADY_OWN) {
1044         g_dbus_method_invocation_return_value (invocation,
1045                 g_variant_new ("(u)", IBUS_BUS_REQUEST_NAME_REPLY_ALREADY_OWNER));
1046         return;
1047     }
1048
1049     owner = bus_name_service_find_owner (service, connection);
1050     /* If connection already in queue, we need remove it at first. */
1051     if (owner != NULL) {
1052         bus_connection_remove_name (connection, name);
1053         bus_name_service_remove_owner (service, owner, NULL);
1054         bus_connection_owner_free (owner);
1055     }
1056
1057     switch (action) {
1058     case ACTION_EXISTS:
1059         g_dbus_method_invocation_return_value (invocation,
1060                 g_variant_new ("(u)", IBUS_BUS_REQUEST_NAME_REPLY_EXISTS));
1061         return;
1062
1063     case ACTION_IN_QUEUE:
1064         owner = bus_connection_owner_new (connection, flags);
1065         g_dbus_method_invocation_return_value (invocation,
1066                 g_variant_new ("(u)", IBUS_BUS_REQUEST_NAME_REPLY_IN_QUEUE));
1067         bus_name_service_add_non_primary_owner (service, owner, dbus);
1068         return;
1069
1070     case ACTION_REPLACE:
1071         bus_connection_add_name (connection, name);
1072         owner = bus_connection_owner_new (connection, flags);
1073         g_dbus_method_invocation_return_value (invocation,
1074                 g_variant_new ("(u)", IBUS_BUS_REQUEST_NAME_REPLY_PRIMARY_OWNER));
1075         bus_name_service_set_primary_owner (service, owner, dbus);
1076         return;
1077
1078     default:
1079         g_assert_not_reached ();
1080     }
1081 }
1082
1083 /**
1084  * bus_dbus_impl_release_name:
1085  *
1086  * Implement the "ReleaseName" method call of the org.freedesktop.DBus interface.
1087  */
1088 static void
1089 bus_dbus_impl_release_name (BusDBusImpl           *dbus,
1090                             BusConnection         *connection,
1091                             GVariant              *parameters,
1092                             GDBusMethodInvocation *invocation)
1093 {
1094     const gchar *name= NULL;
1095     g_variant_get (parameters, "(&s)", &name);
1096
1097     if (name == NULL ||
1098         !g_dbus_is_name (name) ||
1099         g_dbus_is_unique_name (name)) {
1100         g_dbus_method_invocation_return_error (invocation,
1101                         G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1102                         "'%s' is not a legal service name.", name);
1103         return;
1104     }
1105
1106     if (g_strcmp0 (name, "org.freedesktop.DBus") == 0 ||
1107         g_strcmp0 (name, "org.freedesktop.IBus") == 0) {
1108         g_dbus_method_invocation_return_error (invocation,
1109                         G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1110                         "Service name '%s' is owned by IBus.", name);
1111         return;
1112     }
1113
1114     guint retval;
1115     if (g_hash_table_lookup (dbus->names, name) == NULL) {
1116         retval = 2; /* DBUS_RELEASE_NAME_REPLY_NON_EXISTENT */
1117     }
1118     else {
1119         if (bus_connection_remove_name (connection, name)) {
1120             retval = 1; /* DBUS_RELEASE_NAME_REPLY_RELEASED */
1121         }
1122         else {
1123             retval = 3; /* DBUS_RELEASE_NAME_REPLY_NOT_OWNER */
1124         }
1125     }
1126     g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", retval));
1127 }
1128
1129 static gboolean
1130 start_service_timeout_cb (BusMethodCall *call)
1131 {
1132     const gchar *name= NULL;
1133     guint32 flags;              /* currently not used in the D-Bus spec */
1134     g_variant_get (call->parameters, "(&su)", &name, &flags);
1135
1136     g_dbus_method_invocation_return_error (call->invocation,
1137                     G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
1138                     "Timeout reached before starting %s", name);
1139
1140     GList *p = g_list_find (call->dbus->start_service_calls, call);
1141     g_return_val_if_fail (p != NULL, FALSE);
1142
1143     bus_method_call_free ((BusMethodCall *) p->data);
1144     call->dbus->start_service_calls =
1145         g_list_delete_link (call->dbus->start_service_calls, p);
1146
1147     return FALSE;
1148 }
1149
1150 /**
1151  * bus_dbus_impl_start_service_by_name:
1152  *
1153  * Implement the "StartServiceByName" method call of the
1154  * org.freedesktop.DBus interface.
1155  */
1156 static void
1157 bus_dbus_impl_start_service_by_name (BusDBusImpl           *dbus,
1158                                      BusConnection         *connection,
1159                                      GVariant              *parameters,
1160                                      GDBusMethodInvocation *invocation)
1161 {
1162     const gchar *name= NULL;
1163     guint32 flags;              /* currently not used in the D-Bus spec */
1164     g_variant_get (parameters, "(&su)", &name, &flags);
1165
1166     if (name == NULL ||
1167         !g_dbus_is_name (name) ||
1168         g_dbus_is_unique_name (name)) {
1169         g_dbus_method_invocation_return_error (invocation,
1170                         G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1171                         "'%s' is not a legal service name.", name);
1172         return;
1173     }
1174
1175     if (g_strcmp0 (name, "org.freedesktop.DBus") == 0 ||
1176         g_strcmp0 (name, "org.freedesktop.IBus") == 0) {
1177         g_dbus_method_invocation_return_error (invocation,
1178                         G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1179                         "Service name '%s' is owned by IBus.", name);
1180         return;
1181     }
1182
1183     if (g_hash_table_lookup (dbus->names, name) != NULL) {
1184         g_dbus_method_invocation_return_value (invocation,
1185                         g_variant_new ("(u)",
1186                                        IBUS_BUS_START_REPLY_ALREADY_RUNNING));
1187         return;
1188     }
1189
1190     BusRegistry *registry = BUS_DEFAULT_REGISTRY;
1191     BusComponent *component = bus_registry_lookup_component_by_name (registry,
1192                                                                      name);
1193
1194     if (component == NULL || !bus_component_start (component, g_verbose)) {
1195         g_dbus_method_invocation_return_error (invocation,
1196                         G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
1197                         "Failed to start %s", name);
1198         return;
1199     }
1200
1201     BusMethodCall *call = bus_method_call_new (dbus,
1202                                                connection,
1203                                                parameters,
1204                                                invocation);
1205     call->timeout_id = g_timeout_add (g_gdbus_timeout,
1206                                       (GSourceFunc) start_service_timeout_cb,
1207                                       call);
1208     dbus->start_service_calls = g_list_prepend (dbus->start_service_calls,
1209                                                 (gpointer) call);
1210 }
1211
1212 /**
1213  * bus_dbus_impl_name_owner_changed:
1214  *
1215  * The function is called on name-owner-changed signal, typically when g_signal_emit (dbus, NAME_OWNER_CHANGED)
1216  * is called, and broadcasts the signal to clients.
1217  */
1218 static void
1219 bus_dbus_impl_name_owner_changed (BusDBusImpl   *dbus,
1220                                   BusConnection *connection,
1221                                   gchar         *name,
1222                                   gchar         *old_owner,
1223                                   gchar         *new_owner)
1224 {
1225     g_assert (BUS_IS_DBUS_IMPL (dbus));
1226     g_assert (name != NULL);
1227     g_assert (old_owner != NULL);
1228     g_assert (new_owner != NULL);
1229
1230     GDBusMessage *message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
1231                                                        "org.freedesktop.DBus",
1232                                                        "NameOwnerChanged");
1233     g_dbus_message_set_sender (message, "org.freedesktop.DBus");
1234
1235     /* set a non-zero serial to make libdbus happy */
1236     g_dbus_message_set_serial (message, 1);
1237     g_dbus_message_set_body (message,
1238                              g_variant_new ("(sss)", name, old_owner, new_owner));
1239
1240     /* broadcast the message to clients that listen to the signal. */
1241     bus_dbus_impl_dispatch_message_by_rule (dbus, message, NULL);
1242     g_object_unref (message);
1243 }
1244
1245 /**
1246  * bus_dbus_impl_name_lost:
1247  *
1248  * The function is called on name-lost signal, typically when g_signal_emit (dbus, NAME_LOST)
1249  * is called, and broadcasts the signal to clients.
1250  */
1251 static void
1252 bus_dbus_impl_name_lost (BusDBusImpl   *dbus,
1253                          BusConnection *connection,
1254                          gchar         *name)
1255 {
1256     g_assert (BUS_IS_DBUS_IMPL (dbus));
1257     g_assert (name != NULL);
1258
1259     GDBusMessage *message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
1260                                                        "org.freedesktop.DBus",
1261                                                        "NameLost");
1262     g_dbus_message_set_sender (message, "org.freedesktop.DBus");
1263     g_dbus_message_set_destination (message, bus_connection_get_unique_name (connection));
1264
1265     /* set a non-zero serial to make libdbus happy */
1266     g_dbus_message_set_serial (message, 1);
1267     g_dbus_message_set_body (message,
1268                              g_variant_new ("(s)", name));
1269
1270     bus_dbus_impl_forward_message (dbus, connection, message);
1271     g_object_unref (message);
1272 }
1273
1274 /**
1275  * bus_dbus_impl_name_acquired:
1276  *
1277  * The function is called on name-acquired signal, typically when g_signal_emit (dbus, NAME_ACQUIRED)
1278  * is called, and broadcasts the signal to clients.
1279  */
1280 static void
1281 bus_dbus_impl_name_acquired (BusDBusImpl   *dbus,
1282                              BusConnection *connection,
1283                              gchar         *name)
1284 {
1285     g_assert (BUS_IS_DBUS_IMPL (dbus));
1286     g_assert (name != NULL);
1287
1288     GDBusMessage *message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
1289                                                        "org.freedesktop.DBus",
1290                                                        "NameAcquired");
1291     g_dbus_message_set_sender (message, "org.freedesktop.DBus");
1292     g_dbus_message_set_destination (message, bus_connection_get_unique_name (connection));
1293
1294     /* set a non-zero serial to make libdbus happy */
1295     g_dbus_message_set_serial (message, 1);
1296     g_dbus_message_set_body (message,
1297                              g_variant_new ("(s)", name));
1298
1299     bus_dbus_impl_forward_message (dbus, connection, message);
1300     g_object_unref (message);
1301
1302     GList *p = dbus->start_service_calls;
1303     while (p != NULL) {
1304         BusMethodCall *call = p->data;
1305         const gchar *_name= NULL;
1306         guint32 flags;
1307         GList *next = p->next;
1308
1309         g_variant_get (call->parameters, "(&su)", &_name, &flags);
1310         if (g_strcmp0 (name, _name) == 0) {
1311             g_dbus_method_invocation_return_value (call->invocation,
1312                             g_variant_new ("(u)",
1313                                            IBUS_BUS_START_REPLY_SUCCESS));
1314             bus_method_call_free ((BusMethodCall *) p->data);
1315
1316             dbus->start_service_calls =
1317                 g_list_delete_link (dbus->start_service_calls, p);
1318         }
1319         p = next;
1320     }
1321 }
1322
1323 /**
1324  * bus_dbus_impl_service_method_call:
1325  *
1326  * Handle a D-Bus method call from a client. This function overrides an implementation in src/ibusservice.c.
1327  */
1328 static void
1329 bus_dbus_impl_service_method_call (IBusService           *service,
1330                                    GDBusConnection       *dbus_connection,
1331                                    const gchar           *sender,
1332                                    const gchar           *object_path,
1333                                    const gchar           *interface_name,
1334                                    const gchar           *method_name,
1335                                    GVariant              *parameters,
1336                                    GDBusMethodInvocation *invocation)
1337 {
1338     BusDBusImpl *dbus = BUS_DBUS_IMPL (service);
1339
1340     if (g_strcmp0 (interface_name, "org.freedesktop.DBus") != 0) {
1341         IBUS_SERVICE_CLASS (bus_dbus_impl_parent_class)->service_method_call (
1342                                         (IBusService *) dbus,
1343                                         dbus_connection,
1344                                         sender,
1345                                         object_path,
1346                                         interface_name,
1347                                         method_name,
1348                                         parameters,
1349                                         invocation);
1350         return;
1351     }
1352
1353     static const struct {
1354         const gchar *method_name;
1355         void (* method) (BusDBusImpl *, BusConnection *, GVariant *, GDBusMethodInvocation *);
1356     } methods[] =  {
1357         /* DBus interface */
1358         { "Hello",              bus_dbus_impl_hello },
1359         { "ListNames",          bus_dbus_impl_list_names },
1360         { "NameHasOwner",       bus_dbus_impl_name_has_owner },
1361         { "GetNameOwner",       bus_dbus_impl_get_name_owner },
1362         { "ListQueuedOwners",   bus_dbus_impl_list_queued_owners },
1363         { "GetId",              bus_dbus_impl_get_id },
1364         { "AddMatch",           bus_dbus_impl_add_match },
1365         { "RemoveMatch",        bus_dbus_impl_remove_match },
1366         { "RequestName",        bus_dbus_impl_request_name },
1367         { "ReleaseName",        bus_dbus_impl_release_name },
1368         { "StartServiceByName", bus_dbus_impl_start_service_by_name },
1369     };
1370
1371     gint i;
1372     for (i = 0; i < G_N_ELEMENTS (methods); i++) {
1373         if (g_strcmp0 (method_name, methods[i].method_name) == 0) {
1374             BusConnection *connection = bus_connection_lookup (dbus_connection);
1375             g_assert (BUS_IS_CONNECTION (connection));
1376             methods[i].method (dbus, connection, parameters, invocation);
1377             return;
1378         }
1379     }
1380
1381     /* unsupported methods */
1382     g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD,
1383                                            "org.freedesktop.DBus does not support %s", method_name);
1384 }
1385
1386 /**
1387  * bus_dbus_impl_service_get_property:
1388  *
1389  * Handle a D-Bus method call from a client. This function overrides an implementation in src/ibusservice.c.
1390  */
1391 static GVariant *
1392 bus_dbus_impl_service_get_property (IBusService        *service,
1393                                     GDBusConnection    *connection,
1394                                     const gchar        *sender,
1395                                     const gchar        *object_path,
1396                                     const gchar        *interface_name,
1397                                     const gchar        *property_name,
1398                                     GError            **error)
1399 {
1400     /* FIXME implement the function. */
1401     return IBUS_SERVICE_CLASS (bus_dbus_impl_parent_class)->
1402                 service_get_property (service,
1403                                       connection,
1404                                       sender,
1405                                       object_path,
1406                                       interface_name,
1407                                       property_name,
1408                                       error);
1409 }
1410
1411 /**
1412  * bus_dbus_impl_service_set_property:
1413  *
1414  * Handle a D-Bus method call from a client. This function overrides an implementation in src/ibusservice.c.
1415  */
1416 static gboolean
1417 bus_dbus_impl_service_set_property (IBusService        *service,
1418                                     GDBusConnection    *connection,
1419                                     const gchar        *sender,
1420                                     const gchar        *object_path,
1421                                     const gchar        *interface_name,
1422                                     const gchar        *property_name,
1423                                     GVariant           *value,
1424                                     GError            **error)
1425 {
1426     /* FIXME implement the function. */
1427     return IBUS_SERVICE_CLASS (bus_dbus_impl_parent_class)->
1428                 service_set_property (service,
1429                                       connection,
1430                                       sender,
1431                                       object_path,
1432                                       interface_name,
1433                                       property_name,
1434                                       value,
1435                                       error);
1436
1437 }
1438
1439 /**
1440  * bus_dbus_impl_connection_filter_cb:
1441  * @returns: A GDBusMessage that will be processed by bus_dbus_impl_service_method_call. NULL when dropping the message.
1442  *
1443  * A filter function that is called for all incoming and outgoing messages.
1444  * WARNING - this function could be called by the GDBus's worker thread. So you should not call thread unsafe IBus functions.
1445  */
1446 static GDBusMessage *
1447 bus_dbus_impl_connection_filter_cb (GDBusConnection *dbus_connection,
1448                                     GDBusMessage    *message,
1449                                     gboolean         incoming,
1450                                     gpointer         user_data)
1451 {
1452     g_assert (G_IS_DBUS_CONNECTION (dbus_connection));
1453     g_assert (G_IS_DBUS_MESSAGE (message));
1454     g_assert (BUS_IS_DBUS_IMPL (user_data));
1455
1456     BusDBusImpl *dbus = (BusDBusImpl *) user_data;
1457     BusConnection *connection = bus_connection_lookup (dbus_connection);
1458     g_assert (connection != NULL);
1459
1460     if (incoming) {
1461         /* is incoming message */
1462
1463         /* get the destination aka bus name of the message. the destination is set by g_dbus_connection_call_sync (for DBus and IBus messages
1464          * in the IBusBus class) or g_initable_new (for config and context messages in the IBusProxy sub classes.) */
1465         const gchar *destination = g_dbus_message_get_destination (message);
1466         GDBusMessageType message_type = g_dbus_message_get_message_type (message);
1467
1468         if (g_dbus_message_get_locked (message)) {
1469             /* If the message is locked, we need make a copy of it. */
1470             GDBusMessage *new_message = g_dbus_message_copy (message, NULL);
1471             g_assert (new_message != NULL);
1472             g_object_unref (message);
1473             message = new_message;
1474         }
1475
1476         /* connection unique name as sender of the message*/
1477         g_dbus_message_set_sender (message, bus_connection_get_unique_name (connection));
1478
1479         if (g_strcmp0 (destination, "org.freedesktop.IBus") == 0) {
1480             /* the message is sent to IBus service. messages from ibusbus and ibuscontext may fall into this category. */
1481             switch (message_type) {
1482             case G_DBUS_MESSAGE_TYPE_METHOD_CALL:
1483             case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
1484             case G_DBUS_MESSAGE_TYPE_ERROR:
1485                 /* dispatch messages by match rule */
1486                 bus_dbus_impl_dispatch_message_by_rule (dbus, message, NULL);
1487                 return message;
1488             case G_DBUS_MESSAGE_TYPE_SIGNAL:
1489                 /* notreached - signals should not be sent to IBus service. dispatch signal messages by match rule, just in case. */
1490                 bus_dbus_impl_dispatch_message_by_rule (dbus, message, NULL);
1491                 g_object_unref (message);
1492                 g_return_val_if_reached (NULL);  /* return NULL since the service does not handle signals. */
1493             default:
1494                 g_object_unref (message);
1495                 g_return_val_if_reached (NULL);  /* return NULL since the service does not handle signals. */
1496             }
1497         }
1498         else if (g_strcmp0 (destination, "org.freedesktop.DBus") == 0) {
1499             /* the message is sent to DBus service. messages from ibusbus may fall into this category. */
1500             switch (message_type) {
1501             case G_DBUS_MESSAGE_TYPE_METHOD_CALL:
1502             case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
1503             case G_DBUS_MESSAGE_TYPE_ERROR:
1504                 /* dispatch messages by match rule */
1505                 bus_dbus_impl_dispatch_message_by_rule (dbus, message, NULL);
1506                 return message;
1507             case G_DBUS_MESSAGE_TYPE_SIGNAL:
1508                 /* notreached - signals should not be sent to IBus service. dispatch signal messages by match rule, just in case. */
1509                 bus_dbus_impl_dispatch_message_by_rule (dbus, message, NULL);
1510                 g_object_unref (message);
1511                 g_return_val_if_reached (NULL);  /* return NULL since the service does not handle signals. */
1512             default:
1513                 g_object_unref (message);
1514                 g_return_val_if_reached (NULL);  /* return NULL since the service does not handle signals. */
1515             }
1516         }
1517         else if (destination == NULL) {
1518             /* the message is sent to the current connection. communications between ibus-daemon and panel/engines may fall into this
1519              * category since the panel/engine proxies created by ibus-daemon does not set bus name. */
1520             switch (message_type) {
1521             case G_DBUS_MESSAGE_TYPE_SIGNAL:
1522             case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
1523             case G_DBUS_MESSAGE_TYPE_ERROR:
1524                 /* dispatch messages by match rule */
1525                 bus_dbus_impl_dispatch_message_by_rule (dbus, message, NULL);
1526                 return message;
1527             case G_DBUS_MESSAGE_TYPE_METHOD_CALL:
1528                 g_warning ("Unknown method call: destination=NULL, path='%s', interface='%s', member='%s'",
1529                            g_dbus_message_get_path (message),
1530                            g_dbus_message_get_interface (message),
1531                            g_dbus_message_get_member (message));
1532                 bus_dbus_impl_dispatch_message_by_rule (dbus, message, NULL);
1533                 return message; /* return the message, GDBus library will handle it */
1534             default:
1535                 /* notreached. */
1536                 g_object_unref (message);
1537                 g_return_val_if_reached (NULL);  /* return NULL since the service does not handle messages. */
1538             }
1539         }
1540         else {
1541             /* The message is sent to an other service. Forward it.
1542              * For example, the config proxy class in src/ibusconfig.c sets its "g-name" property (i.e. destination) to IBUS_SERVICE_CONFIG. */
1543             bus_dbus_impl_forward_message (dbus, connection, message);
1544             g_object_unref (message);
1545             return NULL;
1546         }
1547     }
1548     else {
1549         /* is outgoing message */
1550         if (g_dbus_message_get_sender (message) == NULL) {
1551             if (g_dbus_message_get_locked (message)) {
1552                 GDBusMessage *new_message = g_dbus_message_copy (message, NULL);
1553                 g_assert (new_message != NULL);
1554                 g_object_unref (message);
1555                 message = new_message;
1556             }
1557             /* If the message is sending from ibus-daemon directly,
1558              * we set the sender to org.freedesktop.DBus */
1559             g_dbus_message_set_sender (message, "org.freedesktop.DBus");
1560         }
1561
1562         /* dispatch the outgoing message by rules. */
1563         bus_dbus_impl_dispatch_message_by_rule (dbus, message, connection);
1564         return message;
1565     }
1566 }
1567
1568 BusDBusImpl *
1569 bus_dbus_impl_get_default (void)
1570 {
1571     static BusDBusImpl *dbus = NULL;
1572
1573     if (dbus == NULL) {
1574         dbus = (BusDBusImpl *) g_object_new (BUS_TYPE_DBUS_IMPL,
1575                                              "object-path", "/org/freedesktop/DBus",
1576                                              NULL);
1577     }
1578
1579     return dbus;
1580 }
1581
1582 static void
1583 bus_dbus_impl_connection_destroy_cb (BusConnection *connection,
1584                                      BusDBusImpl   *dbus)
1585 {
1586     const gchar *unique_name = bus_connection_get_unique_name (connection);
1587     const GList *names = NULL;
1588     BusNameService *service = NULL;
1589
1590     if (unique_name != NULL) {
1591         GList *p = dbus->start_service_calls;
1592         while (p != NULL) {
1593             BusMethodCall *call = p->data;
1594             GList *next = p->next;
1595
1596             if (call->connection == connection) {
1597                 bus_method_call_free ((BusMethodCall *) p->data);
1598                 dbus->start_service_calls =
1599                     g_list_delete_link (dbus->start_service_calls, p);
1600             }
1601             p = next;
1602         }
1603
1604         g_hash_table_remove (dbus->unique_names, unique_name);
1605         g_signal_emit (dbus,
1606                        dbus_signals[NAME_OWNER_CHANGED],
1607                        0,
1608                        connection,
1609                        unique_name,
1610                        unique_name,
1611                        "");
1612     }
1613
1614     /* service->owners is the queue of connections.
1615      * If the connection is the primary owner and
1616      * bus_name_service_remove_owner() is called, the owner is removed
1617      * in the queue and the next owner will become the primary owner
1618      * automatically because service->owners is just a GSList.
1619      * If service->owners == NULL, it's good to remove the service in
1620      * dbus->names.
1621      * I suppose dbus->names are the global queue for every connection
1622      * and connection->names are the private queue of the connection.
1623      */
1624     names = bus_connection_get_names (connection);
1625     while (names != NULL) {
1626         const gchar *name = (const gchar *)names->data;
1627         service = (BusNameService *) g_hash_table_lookup (dbus->names,
1628                                                           name);
1629         g_assert (service != NULL);
1630         BusConnectionOwner *owner = bus_name_service_find_owner (service,
1631                 connection);
1632         g_assert (owner != NULL);
1633         bus_name_service_remove_owner (service, owner, dbus);
1634         if (service->owners == NULL) {
1635             g_hash_table_remove (dbus->names, service->name);
1636         }
1637         bus_connection_owner_free (owner);
1638         names = names->next;
1639     }
1640
1641     dbus->connections = g_list_remove (dbus->connections, connection);
1642     g_object_unref (connection);
1643 }
1644
1645
1646 gboolean
1647 bus_dbus_impl_new_connection (BusDBusImpl   *dbus,
1648                               BusConnection *connection)
1649 {
1650     g_assert (BUS_IS_DBUS_IMPL (dbus));
1651     g_assert (BUS_IS_CONNECTION (connection));
1652     g_assert (g_list_find (dbus->connections, connection) == NULL);
1653
1654     g_object_ref_sink (connection);
1655     dbus->connections = g_list_append (dbus->connections, connection);
1656
1657     bus_connection_set_filter (connection,
1658                     bus_dbus_impl_connection_filter_cb, g_object_ref (dbus), g_object_unref);
1659
1660     g_signal_connect (connection,
1661                       "destroy",
1662                       G_CALLBACK (bus_dbus_impl_connection_destroy_cb),
1663                       dbus);
1664
1665     /* add introspection_xml[] (see above) to the connection. */
1666     ibus_service_register ((IBusService *) dbus,
1667                     bus_connection_get_dbus_connection (connection), NULL);
1668     GList *p;
1669     for (p = dbus->objects; p != NULL; p = p->next) {
1670         /* add all introspection xmls in dbus->objects to the connection. */
1671         ibus_service_register ((IBusService *) p->data,
1672                         bus_connection_get_dbus_connection (connection), NULL);
1673     }
1674     return TRUE;
1675 }
1676
1677 BusConnection *
1678 bus_dbus_impl_get_connection_by_name (BusDBusImpl    *dbus,
1679                                       const gchar    *name)
1680 {
1681     g_assert (BUS_IS_DBUS_IMPL (dbus));
1682     g_assert (name != NULL);
1683
1684     if (G_LIKELY (g_dbus_is_unique_name (name))) {
1685         return (BusConnection *) g_hash_table_lookup (dbus->unique_names, name);
1686     }
1687     else {
1688         BusNameService *service;
1689         BusConnectionOwner *owner;
1690
1691         service = (BusNameService *) g_hash_table_lookup (dbus->names, name);
1692         if (service == NULL) {
1693             return NULL;
1694         }
1695         owner = bus_name_service_get_primary_owner (service);
1696         return owner ? owner->conn : NULL;
1697     }
1698 }
1699
1700 typedef struct _BusForwardData BusForwardData;
1701 struct _BusForwardData {
1702     GDBusMessage *message;
1703     BusConnection *sender_connection;
1704 };
1705
1706 /**
1707  * bus_dbus_impl_forward_message_ible_cb:
1708  *
1709  * Process the first element of the dbus->forward_queue. The first element is forwarded by g_dbus_connection_send_message.
1710  */
1711 static gboolean
1712 bus_dbus_impl_forward_message_idle_cb (BusDBusImpl   *dbus)
1713 {
1714     g_return_val_if_fail (dbus->forward_queue != NULL, FALSE);
1715
1716     g_mutex_lock (dbus->forward_lock);
1717     BusForwardData *data = (BusForwardData *) dbus->forward_queue->data;
1718     dbus->forward_queue = g_list_delete_link (dbus->forward_queue, dbus->forward_queue);
1719     gboolean has_message = (dbus->forward_queue != NULL);
1720     g_mutex_unlock (dbus->forward_lock);
1721
1722     do {
1723         const gchar *destination = g_dbus_message_get_destination (data->message);
1724         BusConnection *dest_connection = NULL;
1725         if (destination != NULL)
1726             dest_connection = bus_dbus_impl_get_connection_by_name (dbus, destination);
1727         if (dest_connection != NULL) {
1728             /* FIXME workaround for gdbus. gdbus can not set an empty body message with signature '()' */
1729             if (g_dbus_message_get_body (data->message) == NULL)
1730                 g_dbus_message_set_signature (data->message, NULL);
1731             GError *error = NULL;
1732             gboolean retval = g_dbus_connection_send_message (
1733                                         bus_connection_get_dbus_connection (dest_connection),
1734                                         data->message,
1735                                         G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL,
1736                                         NULL, &error);
1737             if (retval)
1738                 break;
1739             g_warning ("forward message failed:  %s.", error->message);
1740             g_error_free (error);
1741         }
1742         /* can not forward message */
1743         if (g_dbus_message_get_message_type (data->message) != G_DBUS_MESSAGE_TYPE_METHOD_CALL) {
1744             /* skip non method messages */
1745             break;
1746         }
1747
1748         /* reply an error message, if forward method call message failed. */
1749         GDBusMessage *reply_message = g_dbus_message_new_method_error (data->message,
1750                             "org.freedesktop.DBus.Error.ServiceUnknown ",
1751                             "The service name is '%s'.", destination);
1752         g_dbus_message_set_sender (reply_message, "org.freedesktop.DBus");
1753         g_dbus_message_set_destination (reply_message, bus_connection_get_unique_name (data->sender_connection));
1754         g_dbus_connection_send_message (bus_connection_get_dbus_connection (data->sender_connection),
1755                                         reply_message,
1756                                         G_DBUS_SEND_MESSAGE_FLAGS_NONE,
1757                                         NULL, NULL);
1758         g_object_unref (reply_message);
1759     } while (0);
1760
1761     g_object_unref (data->message);
1762     g_object_unref (data->sender_connection);
1763     g_slice_free (BusForwardData, data);
1764     return has_message;
1765 }
1766
1767 void
1768 bus_dbus_impl_forward_message (BusDBusImpl   *dbus,
1769                                BusConnection *connection,
1770                                GDBusMessage  *message)
1771 {
1772     /* WARNING - this function could be called by the GDBus's worker thread. So you should not call thread unsafe IBus functions. */
1773     g_assert (BUS_IS_DBUS_IMPL (dbus));
1774     g_assert (BUS_IS_CONNECTION (connection));
1775     g_assert (G_IS_DBUS_MESSAGE (message));
1776
1777     if (G_UNLIKELY (IBUS_OBJECT_DESTROYED (dbus)))
1778         return;
1779     /* FIXME the check above might not be sufficient. dbus object could be destroyed in the main thread right after the check, though the
1780      * dbus structure itself would not be freed (since the dbus object is ref'ed in bus_dbus_impl_new_connection.)
1781      * Anyway, it'd be better to investigate whether the thread safety issue could cause any real problems. */
1782
1783     BusForwardData *data = g_slice_new (BusForwardData);
1784     data->message = g_object_ref (message);
1785     data->sender_connection = g_object_ref (connection);
1786
1787     g_mutex_lock (dbus->forward_lock);
1788     gboolean is_running = (dbus->forward_queue != NULL);
1789     dbus->forward_queue = g_list_append (dbus->forward_queue, data);
1790     g_mutex_unlock (dbus->forward_lock);
1791
1792     if (!is_running) {
1793         g_idle_add_full (G_PRIORITY_DEFAULT,
1794                 (GSourceFunc) bus_dbus_impl_forward_message_idle_cb,
1795                 g_object_ref (dbus), (GDestroyNotify) g_object_unref);
1796         /* the idle callback function will be called from the ibus's main thread. */
1797     }
1798 }
1799
1800 static BusDispatchData *
1801 bus_dispatch_data_new (GDBusMessage  *message,
1802                        BusConnection *skip_connection)
1803 {
1804     BusDispatchData *data = g_slice_new (BusDispatchData);
1805
1806     data->message = (GDBusMessage *) g_object_ref (message);
1807     if (skip_connection) {
1808         data->skip_connection = (BusConnection *) g_object_ref (skip_connection);
1809     }
1810     else {
1811         data->skip_connection = NULL;
1812     }
1813     return data;
1814 }
1815
1816 static void
1817 bus_dispatch_data_free (BusDispatchData *data)
1818 {
1819     g_object_unref (data->message);
1820     if (data->skip_connection)
1821         g_object_unref (data->skip_connection);
1822     g_slice_free (BusDispatchData, data);
1823 }
1824
1825 /**
1826  * bus_dbus_impl_dispatch_message_by_rule_idle_cb:
1827  *
1828  * Process the first element of the dbus->dispatch_queue.
1829  */
1830 static gboolean
1831 bus_dbus_impl_dispatch_message_by_rule_idle_cb (BusDBusImpl *dbus)
1832 {
1833     g_return_val_if_fail (dbus->dispatch_queue != NULL, FALSE);
1834
1835     if (G_UNLIKELY (IBUS_OBJECT_DESTROYED (dbus))) {
1836         /* dbus was destryed */
1837         g_mutex_lock (dbus->dispatch_lock);
1838         g_list_free_full (dbus->dispatch_queue,
1839                           (GDestroyNotify) bus_dispatch_data_free);
1840         dbus->dispatch_queue = NULL;
1841         g_mutex_unlock (dbus->dispatch_lock);
1842         return FALSE; /* return FALSE to prevent this callback to be called again. */
1843     }
1844
1845     /* remove fist node */
1846     g_mutex_lock (dbus->dispatch_lock);
1847     BusDispatchData *data = (BusDispatchData *) dbus->dispatch_queue->data;
1848     dbus->dispatch_queue = g_list_delete_link (dbus->dispatch_queue, dbus->dispatch_queue);
1849     gboolean has_message = (dbus->dispatch_queue != NULL);
1850     g_mutex_unlock (dbus->dispatch_lock);
1851
1852     GList *link = NULL;
1853     GList *recipients = NULL;
1854
1855     /* check each match rules, and get recipients */
1856     for (link = dbus->rules; link != NULL; link = link->next) {
1857         GList *list = bus_match_rule_get_recipients ((BusMatchRule *) link->data,
1858                                                      data->message);
1859         recipients = g_list_concat (recipients, list);
1860     }
1861
1862     /* send message to each recipients */
1863     for (link = recipients; link != NULL; link = link->next) {
1864         BusConnection *connection = (BusConnection *) link->data;
1865         if (G_LIKELY (connection != data->skip_connection)) {
1866             g_dbus_connection_send_message (bus_connection_get_dbus_connection (connection),
1867                                             data->message,
1868                                             G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL,
1869                                             NULL, NULL);
1870         }
1871     }
1872     g_list_free (recipients);
1873     bus_dispatch_data_free (data);
1874
1875     return has_message;  /* remove this idle callback if no message is left by returning FALSE. */
1876 }
1877
1878 void
1879 bus_dbus_impl_dispatch_message_by_rule (BusDBusImpl     *dbus,
1880                                         GDBusMessage    *message,
1881                                         BusConnection   *skip_connection)
1882 {
1883     /* WARNING - this function could be called by the GDBus's worker thread. So you should not call thread unsafe IBus functions. */
1884     g_assert (BUS_IS_DBUS_IMPL (dbus));
1885     g_assert (message != NULL);
1886     g_assert (skip_connection == NULL || BUS_IS_CONNECTION (skip_connection));
1887
1888     if (G_UNLIKELY (IBUS_OBJECT_DESTROYED (dbus)))
1889         return;
1890     /* FIXME - see the FIXME comment in bus_dbus_impl_forward_message. */
1891
1892     static GQuark dispatched_quark = 0;
1893     if (dispatched_quark == 0) {
1894         dispatched_quark = g_quark_from_static_string ("DISPATCHED");
1895     }
1896
1897     /* A message sent or forwarded by bus_dbus_impl_dispatch_message_by_rule_idle_cb is also processed by the filter callback.
1898      * If this message has been dispatched by rule, do nothing. */
1899     if (g_object_get_qdata ((GObject *) message, dispatched_quark) != NULL)
1900         return;
1901     g_object_set_qdata ((GObject *) message, dispatched_quark, GINT_TO_POINTER (1));
1902
1903     /* append dispatch data into the queue, and start idle task if necessary */
1904     g_mutex_lock (dbus->dispatch_lock);
1905     gboolean is_running = (dbus->dispatch_queue != NULL);
1906     dbus->dispatch_queue = g_list_append (dbus->dispatch_queue,
1907                     bus_dispatch_data_new (message, skip_connection));
1908     g_mutex_unlock (dbus->dispatch_lock);
1909     if (!is_running) {
1910         g_idle_add_full (G_PRIORITY_DEFAULT,
1911                          (GSourceFunc) bus_dbus_impl_dispatch_message_by_rule_idle_cb,
1912                          g_object_ref (dbus),
1913                          (GDestroyNotify) g_object_unref);
1914         /* the idle callback function will be called from the ibus's main thread. */
1915     }
1916 }
1917
1918 static void
1919 bus_dbus_impl_object_destroy_cb (IBusService *object,
1920                                  BusDBusImpl *dbus)
1921 {
1922     bus_dbus_impl_unregister_object (dbus, object);
1923 }
1924
1925
1926 gboolean
1927 bus_dbus_impl_register_object (BusDBusImpl *dbus,
1928                                IBusService *object)
1929 {
1930     g_assert (BUS_IS_DBUS_IMPL (dbus));
1931     g_assert (IBUS_IS_SERVICE (object));
1932
1933     if (G_UNLIKELY (IBUS_OBJECT_DESTROYED (dbus))) {
1934         return FALSE;
1935     }
1936
1937     dbus->objects = g_list_prepend (dbus->objects, g_object_ref (object));
1938     g_signal_connect (object, "destroy",
1939                       G_CALLBACK (bus_dbus_impl_object_destroy_cb), dbus);
1940
1941     GList *p;
1942     for (p = dbus->connections; p != NULL; p = p->next) {
1943         GDBusConnection *connection = bus_connection_get_dbus_connection ((BusConnection *) p->data);
1944         if (connection != ibus_service_get_connection ((IBusService *) object))
1945             ibus_service_register ((IBusService *) object,
1946                             bus_connection_get_dbus_connection ((BusConnection *) p->data), NULL);
1947     }
1948     return TRUE;
1949 }
1950
1951 gboolean
1952 bus_dbus_impl_unregister_object (BusDBusImpl *dbus,
1953                                  IBusService *object)
1954 {
1955     g_assert (BUS_IS_DBUS_IMPL (dbus));
1956     g_assert (IBUS_IS_SERVICE (object));
1957
1958     GList *p = g_list_find (dbus->objects, object);
1959     if (p == NULL)
1960         return FALSE;
1961
1962     g_signal_handlers_disconnect_by_func (object,
1963                     G_CALLBACK (bus_dbus_impl_object_destroy_cb), dbus);
1964     dbus->objects = g_list_delete_link (dbus->objects, p);
1965     if (!IBUS_OBJECT_DESTROYED (object)) {
1966         GList *p;
1967         for (p = dbus->connections; p != NULL; p = p->next) {
1968             ibus_service_unregister ((IBusService *) object,
1969                             bus_connection_get_dbus_connection ((BusConnection *) p->data));
1970         }
1971     }
1972     g_object_unref (object);
1973
1974     return TRUE;
1975 }
1976