2005-01-26 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-bus.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-bus.c  Convenience functions for communicating with the bus.
3  *
4  * Copyright (C) 2003  CodeFactory AB
5  * Copyright (C) 2003  Red Hat, Inc.
6  *
7  * Licensed under the Academic Free License version 2.1
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include "dbus-bus.h"
26 #include "dbus-protocol.h"
27 #include "dbus-internals.h"
28 #include "dbus-message.h"
29 #include <string.h>
30
31 /**
32  * @defgroup DBusBus Message bus APIs
33  * @ingroup DBus
34  * @brief Functions for communicating with the message bus
35  *
36  * @todo right now the default address of the system bus is hardcoded,
37  * so if you change it in the global config file suddenly you have to
38  * set DBUS_SYSTEM_BUS_ADDRESS env variable.  Might be nice if the
39  * client lib somehow read the config file, or if the bus on startup
40  * somehow wrote out its address to a well-known spot, but might also
41  * not be worth it.
42  */
43
44 /**
45  * @defgroup DBusBusInternals Message bus APIs internals
46  * @ingroup DBusInternals
47  * @brief Internals of functions for communicating with the message bus
48  *
49  * @{
50  */
51
52 /**
53  * Block of message-bus-related data we attach to each
54  * #DBusConnection used with these convenience functions.
55  *
56  *
57  * @todo get rid of most of these; they should be done
58  * with DBusGProxy and the Qt equivalent, i.e. the same
59  * way any other interface would be used.
60  */
61 typedef struct
62 {
63   DBusConnection *connection; /**< Connection we're associated with */
64   char *unique_name; /**< Unique name of this connection */
65
66   unsigned int is_well_known : 1; /**< Is one of the well-known connections in our global array */
67 } BusData;
68
69 /** The slot we have reserved to store BusData.
70  */
71 static dbus_int32_t bus_data_slot = -1;
72
73 /** Number of bus types */
74 #define N_BUS_TYPES 3
75
76 static DBusConnection *bus_connections[N_BUS_TYPES];
77 static char *bus_connection_addresses[N_BUS_TYPES] = { NULL, NULL, NULL };
78
79 static DBusBusType activation_bus_type = DBUS_BUS_STARTER;
80
81 static dbus_bool_t initialized = FALSE;
82
83 /**
84  * Lock for globals in this file
85  */
86 _DBUS_DEFINE_GLOBAL_LOCK (bus);
87
88 static void
89 addresses_shutdown_func (void *data)
90 {
91   int i;
92
93   i = 0;
94   while (i < N_BUS_TYPES)
95     {
96       if (bus_connections[i] != NULL)
97         _dbus_warn ("dbus_shutdown() called but connections were still live!");
98       
99       dbus_free (bus_connection_addresses[i]);
100       bus_connection_addresses[i] = NULL;
101       ++i;
102     }
103
104   activation_bus_type = DBUS_BUS_STARTER;
105 }
106
107 static dbus_bool_t
108 get_from_env (char           **connection_p,
109               const char      *env_var)
110 {
111   const char *s;
112   
113   _dbus_assert (*connection_p == NULL);
114   
115   s = _dbus_getenv (env_var);
116   if (s == NULL || *s == '\0')
117     return TRUE; /* successfully didn't use the env var */
118   else
119     {
120       *connection_p = _dbus_strdup (s);
121       return *connection_p != NULL;
122     }
123 }
124
125 static dbus_bool_t
126 init_connections_unlocked (void)
127 {
128   if (!initialized)
129     {
130       const char *s;
131       int i;
132
133       i = 0;
134       while (i < N_BUS_TYPES)
135         {
136           bus_connections[i] = NULL;
137           ++i;
138         }
139
140       /* Don't init these twice, we may run this code twice if
141        * init_connections_unlocked() fails midway through.
142        * In practice, each block below should contain only one
143        * "return FALSE" or running through twice may not
144        * work right.
145        */
146       
147        if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
148          {
149            _dbus_verbose ("Filling in system bus address...\n");
150            
151            if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SYSTEM],
152                               "DBUS_SYSTEM_BUS_ADDRESS"))
153              return FALSE;
154          }
155
156                   
157        if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
158          {
159            /* Use default system bus address if none set in environment */
160            bus_connection_addresses[DBUS_BUS_SYSTEM] =
161              _dbus_strdup (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS);
162            if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
163              return FALSE;
164            
165            _dbus_verbose ("  used default system bus \"%s\"\n",
166                           bus_connection_addresses[DBUS_BUS_SYSTEM]);
167          }
168        else
169          _dbus_verbose ("  used env var system bus \"%s\"\n",
170                         bus_connection_addresses[DBUS_BUS_SYSTEM]);
171           
172       if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL)
173         {
174           _dbus_verbose ("Filling in session bus address...\n");
175           
176           if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SESSION],
177                              "DBUS_SESSION_BUS_ADDRESS"))
178             return FALSE;
179           _dbus_verbose ("  \"%s\"\n", bus_connection_addresses[DBUS_BUS_SESSION] ?
180                          bus_connection_addresses[DBUS_BUS_SESSION] : "none set");
181         }
182
183       if (bus_connection_addresses[DBUS_BUS_STARTER] == NULL)
184         {
185           _dbus_verbose ("Filling in activation bus address...\n");
186           
187           if (!get_from_env (&bus_connection_addresses[DBUS_BUS_STARTER],
188                              "DBUS_STARTER_ADDRESS"))
189             return FALSE;
190           
191           _dbus_verbose ("  \"%s\"\n", bus_connection_addresses[DBUS_BUS_STARTER] ?
192                          bus_connection_addresses[DBUS_BUS_STARTER] : "none set");
193         }
194
195
196       if (bus_connection_addresses[DBUS_BUS_STARTER] != NULL)
197         {
198           s = _dbus_getenv ("DBUS_STARTER_BUS_TYPE");
199               
200           if (s != NULL)
201             {
202               _dbus_verbose ("Bus activation type was set to \"%s\"\n", s);
203                   
204               if (strcmp (s, "system") == 0)
205                 activation_bus_type = DBUS_BUS_SYSTEM;
206               else if (strcmp (s, "session") == 0)
207                 activation_bus_type = DBUS_BUS_SESSION;
208             }
209         }
210       else
211         {
212           /* Default to the session bus instead if available */
213           if (bus_connection_addresses[DBUS_BUS_SESSION] != NULL)
214             {
215               bus_connection_addresses[DBUS_BUS_STARTER] =
216                 _dbus_strdup (bus_connection_addresses[DBUS_BUS_SESSION]);
217               if (bus_connection_addresses[DBUS_BUS_STARTER] == NULL)
218                 return FALSE;
219             }
220         }
221       
222       /* If we return FALSE we have to be sure that restarting
223        * the above code will work right
224        */
225       
226       if (!_dbus_setenv ("DBUS_ACTIVATION_ADDRESS", NULL))
227         return FALSE;
228
229       if (!_dbus_setenv ("DBUS_ACTIVATION_BUS_TYPE", NULL))
230         return FALSE;
231       
232       if (!_dbus_register_shutdown_func (addresses_shutdown_func,
233                                          NULL))
234         return FALSE;
235       
236       initialized = TRUE;
237     }
238
239   return initialized;
240 }
241
242 static void
243 bus_data_free (void *data)
244 {
245   BusData *bd = data;
246   
247   if (bd->is_well_known)
248     {
249       int i;
250       _DBUS_LOCK (bus);
251       /* We may be stored in more than one slot */
252       i = 0;
253       while (i < N_BUS_TYPES)
254         {
255           if (bus_connections[i] == bd->connection)
256             bus_connections[i] = NULL;
257           
258           ++i;
259         }
260       _DBUS_UNLOCK (bus);
261     }
262   
263   dbus_free (bd->unique_name);
264   dbus_free (bd);
265
266   dbus_connection_free_data_slot (&bus_data_slot);
267 }
268
269 static BusData*
270 ensure_bus_data (DBusConnection *connection)
271 {
272   BusData *bd;
273
274   if (!dbus_connection_allocate_data_slot (&bus_data_slot))
275     return NULL;
276
277   bd = dbus_connection_get_data (connection, bus_data_slot);
278   if (bd == NULL)
279     {      
280       bd = dbus_new0 (BusData, 1);
281       if (bd == NULL)
282         {
283           dbus_connection_free_data_slot (&bus_data_slot);
284           return NULL;
285         }
286
287       bd->connection = connection;
288       
289       if (!dbus_connection_set_data (connection, bus_data_slot, bd,
290                                      bus_data_free))
291         {
292           dbus_free (bd);
293           dbus_connection_free_data_slot (&bus_data_slot);
294           return NULL;
295         }
296
297       /* Data slot refcount now held by the BusData */
298     }
299   else
300     {
301       dbus_connection_free_data_slot (&bus_data_slot);
302     }
303
304   return bd;
305 }
306
307 /** @} */ /* end of implementation details docs */
308
309 /**
310  * @addtogroup DBusBus
311  * @{
312  */
313
314 /**
315  * Connects to a bus daemon and registers the client with it.  If a
316  * connection to the bus already exists, then that connection is
317  * returned.  Caller owns a reference to the bus.
318  *
319  * @todo alex thinks we should nullify the connection when we get a disconnect-message.
320  *
321  * @param type bus type
322  * @param error address where an error can be returned.
323  * @returns a DBusConnection with new ref
324  */
325 DBusConnection *
326 dbus_bus_get (DBusBusType  type,
327               DBusError   *error)
328 {
329   const char *address;
330   DBusConnection *connection;
331   BusData *bd;
332   DBusBusType address_type;
333
334   _dbus_return_val_if_fail (type >= 0 && type < N_BUS_TYPES, NULL);
335   _dbus_return_val_if_error_is_set (error, NULL);
336
337   _DBUS_LOCK (bus);
338
339   if (!init_connections_unlocked ())
340     {
341       _DBUS_UNLOCK (bus);
342       _DBUS_SET_OOM (error);
343       return NULL;
344     }
345
346   /* We want to use the activation address even if the
347    * activating bus is the session or system bus,
348    * per the spec.
349    */
350   address_type = type;
351   
352   /* Use the real type of the activation bus for getting its
353    * connection, but only if the real type's address is available. (If
354    * the activating bus isn't a well-known bus then
355    * activation_bus_type == DBUS_BUS_STARTER)
356    */
357   if (type == DBUS_BUS_STARTER &&
358       bus_connection_addresses[activation_bus_type] != NULL)
359     type = activation_bus_type;
360   
361   if (bus_connections[type] != NULL)
362     {
363       connection = bus_connections[type];
364       dbus_connection_ref (connection);
365       
366       _DBUS_UNLOCK (bus);
367       return connection;
368     }
369
370   address = bus_connection_addresses[address_type];
371   if (address == NULL)
372     {
373       dbus_set_error (error, DBUS_ERROR_FAILED,
374                       "Unable to determine the address of the message bus");
375       _DBUS_UNLOCK (bus);
376       return NULL;
377     }
378
379   connection = dbus_connection_open (address, error);
380   
381   if (!connection)
382     {
383       _DBUS_ASSERT_ERROR_IS_SET (error);
384       _DBUS_UNLOCK (bus);
385       return NULL;
386     }
387
388   /* By default we're bound to the lifecycle of
389    * the message bus.
390    */
391   dbus_connection_set_exit_on_disconnect (connection,
392                                           TRUE);
393   
394   if (!dbus_bus_register (connection, error))
395     {
396       _DBUS_ASSERT_ERROR_IS_SET (error);
397       dbus_connection_disconnect (connection);
398       dbus_connection_unref (connection);
399
400       _DBUS_UNLOCK (bus);
401       return NULL;
402     }
403
404   bus_connections[type] = connection;
405   bd = ensure_bus_data (connection);
406   _dbus_assert (bd != NULL);
407
408   bd->is_well_known = TRUE;
409
410   _DBUS_UNLOCK (bus);
411   return connection;
412 }
413
414
415 /**
416  * Registers a connection with the bus. This must be the first
417  * thing an application does when connecting to the message bus.
418  * If registration succeeds, the unique name will be set,
419  * and can be obtained using dbus_bus_get_unique_name().
420  * 
421  * @param connection the connection
422  * @param error place to store errors
423  * @returns #TRUE on success
424  */
425 dbus_bool_t
426 dbus_bus_register (DBusConnection *connection,
427                    DBusError      *error)
428 {
429   DBusMessage *message, *reply;
430   char *name;
431   BusData *bd;
432   dbus_bool_t retval;
433
434   _dbus_return_val_if_fail (connection != NULL, FALSE);
435   _dbus_return_val_if_error_is_set (error, FALSE);
436
437   retval = FALSE;
438   
439   bd = ensure_bus_data (connection);
440   if (bd == NULL)
441     {
442       _DBUS_SET_OOM (error);
443       return FALSE;
444     }
445
446   if (bd->unique_name != NULL)
447     {
448       _dbus_warn ("Attempt to register the same DBusConnection with the message bus, but it is already registered\n");
449       /* This isn't an error, it's a programming bug. We'll be nice
450        * and not _dbus_assert_not_reached()
451        */
452       return TRUE;
453     }
454   
455   message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
456                                           DBUS_PATH_ORG_FREEDESKTOP_DBUS,
457                                           DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
458                                           "Hello"); 
459
460   if (!message)
461     {
462       _DBUS_SET_OOM (error);
463       return FALSE;
464     }
465   
466   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
467
468   dbus_message_unref (message);
469   
470   if (reply == NULL)
471     goto out;
472   else if (dbus_set_error_from_message (error, reply))
473     goto out;
474   else if (!dbus_message_get_args (reply, error,
475                                    DBUS_TYPE_STRING, &name,
476                                    DBUS_TYPE_INVALID))
477     goto out;
478   
479   bd->unique_name = _dbus_strdup (name);
480   if (bd->unique_name == NULL)
481     {
482       _DBUS_SET_OOM (error);
483       goto out;
484     }
485   
486   retval = TRUE;
487   
488  out:
489   if (reply)
490     dbus_message_unref (reply);
491
492   if (!retval)
493     _DBUS_ASSERT_ERROR_IS_SET (error);
494   
495   return retval;
496 }
497
498
499 /**
500  * Sets the unique name of the connection.  Can only be used if you
501  * registered with the bus manually (i.e. if you did not call
502  * dbus_bus_register()). Can only be called once per connection.
503  *
504  * @param connection the connection
505  * @param unique_name the unique name
506  * @returns #FALSE if not enough memory
507  */
508 dbus_bool_t
509 dbus_bus_set_unique_name (DBusConnection *connection,
510                           const char     *unique_name)
511 {
512   BusData *bd;
513
514   _dbus_return_val_if_fail (connection != NULL, FALSE);
515   _dbus_return_val_if_fail (unique_name != NULL, FALSE);
516   
517   bd = ensure_bus_data (connection);
518   if (bd == NULL)
519     return FALSE;
520
521   _dbus_assert (bd->unique_name == NULL);
522   
523   bd->unique_name = _dbus_strdup (unique_name);
524   return bd->unique_name != NULL;
525 }
526
527 /**
528  * Gets the unique name of the connection.  Only possible after the
529  * connection has been registered with the message bus.
530  *
531  * @param connection the connection
532  * @returns the unique name
533  */
534 const char*
535 dbus_bus_get_unique_name (DBusConnection *connection)
536 {
537   BusData *bd;
538
539   _dbus_return_val_if_fail (connection != NULL, NULL);
540   
541   bd = ensure_bus_data (connection);
542   if (bd == NULL)
543     return NULL;
544   
545   return bd->unique_name;
546 }
547
548 /**
549  * Asks the bus to return the uid of the named
550  * connection.
551  *
552  * @param connection the connection
553  * @param name a name owned by the connection
554  * @param error location to store the error
555  * @returns a result code, -1 if error is set
556  */ 
557 unsigned long
558 dbus_bus_get_unix_user (DBusConnection *connection,
559                         const char     *name,
560                         DBusError      *error)
561 {
562   DBusMessage *message, *reply;
563   dbus_uint32_t uid;
564
565   _dbus_return_val_if_fail (connection != NULL, DBUS_UID_UNSET);
566   _dbus_return_val_if_fail (name != NULL, DBUS_UID_UNSET);
567   _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), DBUS_UID_UNSET);
568   _dbus_return_val_if_error_is_set (error, DBUS_UID_UNSET);
569   
570   message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
571                                           DBUS_PATH_ORG_FREEDESKTOP_DBUS,
572                                           DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
573                                           "GetConnectionUnixUser");
574
575   if (message == NULL)
576     {
577       _DBUS_SET_OOM (error);
578       return DBUS_UID_UNSET;
579     }
580  
581   if (!dbus_message_append_args (message,
582                                  DBUS_TYPE_STRING, &name,
583                                  DBUS_TYPE_INVALID))
584     {
585       dbus_message_unref (message);
586       _DBUS_SET_OOM (error);
587       return DBUS_UID_UNSET;
588     }
589   
590   reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
591                                                      error);
592   
593   dbus_message_unref (message);
594   
595   if (reply == NULL)
596     {
597       _DBUS_ASSERT_ERROR_IS_SET (error);
598       return DBUS_UID_UNSET;
599     }  
600
601   if (dbus_set_error_from_message (error, reply))
602     {
603       _DBUS_ASSERT_ERROR_IS_SET (error);
604       dbus_message_unref (reply);
605       return DBUS_UID_UNSET;
606     }
607   
608   if (!dbus_message_get_args (reply, error,
609                               DBUS_TYPE_UINT32, &uid,
610                               DBUS_TYPE_INVALID))
611     {
612       _DBUS_ASSERT_ERROR_IS_SET (error);
613       dbus_message_unref (reply);
614       return DBUS_UID_UNSET;
615     }
616
617   dbus_message_unref (reply);
618   
619   return (unsigned long) uid;
620 }
621
622
623 /**
624  * Asks the bus to assign the given name to this connection.
625  *
626  * @todo these docs are not complete, need to document the
627  * return value and flags
628  * 
629  * @todo if we get an error reply, it has to be converted into
630  * DBusError and returned
631  *
632  * @param connection the connection
633  * @param name the name to request
634  * @param flags flags
635  * @param error location to store the error
636  * @returns a result code, -1 if error is set
637  */ 
638 int
639 dbus_bus_request_name (DBusConnection *connection,
640                        const char     *name,
641                        unsigned int    flags,
642                        DBusError      *error)
643 {
644   DBusMessage *message, *reply;
645   dbus_uint32_t result;
646
647   _dbus_return_val_if_fail (connection != NULL, 0);
648   _dbus_return_val_if_fail (name != NULL, 0);
649   _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), 0);
650   _dbus_return_val_if_error_is_set (error, 0);
651   
652   message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
653                                           DBUS_PATH_ORG_FREEDESKTOP_DBUS,
654                                           DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
655                                           "RequestName");
656
657   if (message == NULL)
658     {
659       _DBUS_SET_OOM (error);
660       return -1;
661     }
662  
663   if (!dbus_message_append_args (message,
664                                  DBUS_TYPE_STRING, &name,
665                                  DBUS_TYPE_UINT32, &flags,
666                                  DBUS_TYPE_INVALID))
667     {
668       dbus_message_unref (message);
669       _DBUS_SET_OOM (error);
670       return -1;
671     }
672   
673   reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
674                                                      error);
675   
676   dbus_message_unref (message);
677   
678   if (reply == NULL)
679     {
680       _DBUS_ASSERT_ERROR_IS_SET (error);
681       return -1;
682     }  
683
684   if (dbus_set_error_from_message (error, reply))
685     {
686       _DBUS_ASSERT_ERROR_IS_SET (error);
687       dbus_message_unref (reply);
688       return -1;
689     }
690   
691   if (!dbus_message_get_args (reply, error,
692                               DBUS_TYPE_UINT32, &result,
693                               DBUS_TYPE_INVALID))
694     {
695       _DBUS_ASSERT_ERROR_IS_SET (error);
696       dbus_message_unref (reply);
697       return -1;
698     }
699
700   dbus_message_unref (reply);
701   
702   return result;
703 }
704
705 /**
706  * Checks whether a certain name has an owner.
707  *
708  * @param connection the connection
709  * @param name the name
710  * @param error location to store any errors
711  * @returns #TRUE if the name exists, #FALSE if not or on error
712  */
713 dbus_bool_t
714 dbus_bus_name_has_owner (DBusConnection *connection,
715                          const char     *name,
716                          DBusError      *error)
717 {
718   DBusMessage *message, *reply;
719   dbus_bool_t exists;
720
721   _dbus_return_val_if_fail (connection != NULL, FALSE);
722   _dbus_return_val_if_fail (name != NULL, FALSE);
723   _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), FALSE);
724   _dbus_return_val_if_error_is_set (error, FALSE);
725   
726   message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
727                                           DBUS_PATH_ORG_FREEDESKTOP_DBUS,
728                                           DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
729                                           "NameHasOwner");
730   if (message == NULL)
731     {
732       _DBUS_SET_OOM (error);
733       return FALSE;
734     }
735   
736   if (!dbus_message_append_args (message,
737                                  DBUS_TYPE_STRING, &name,
738                                  DBUS_TYPE_INVALID))
739     {
740       dbus_message_unref (message);
741       _DBUS_SET_OOM (error);
742       return FALSE;
743     }
744   
745   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
746   dbus_message_unref (message);
747
748   if (reply == NULL)
749     {
750       _DBUS_ASSERT_ERROR_IS_SET (error);
751       return FALSE;
752     }
753
754   if (!dbus_message_get_args (reply, error,
755                               DBUS_TYPE_BOOLEAN, &exists,
756                               DBUS_TYPE_INVALID))
757     {
758       _DBUS_ASSERT_ERROR_IS_SET (error);
759       dbus_message_unref (reply);
760       return FALSE;
761     }
762   
763   dbus_message_unref (reply);
764   return exists;
765 }
766
767 /**
768  * Starts a service that will request ownership of the given name.
769  * The returned result will be one of be one of
770  * #DBUS_START_REPLY_SUCCESS or #DBUS_START_REPLY_ALREADY_RUNNING if
771  * successful.  Pass #NULL if you don't care about the result.
772  *
773  * @param connection the connection
774  * @param name the name we want the new service to request
775  * @param flags the flags
776  * @param result a place to store the result or #NULL
777  * @param error location to store any errors
778  * @returns #TRUE if the activation succeeded, #FALSE if not
779  *
780  * @todo document what the flags do
781  */
782 dbus_bool_t
783 dbus_bus_start_service_by_name (DBusConnection *connection,
784                                 const char     *name,
785                                 dbus_uint32_t   flags,
786                                 dbus_uint32_t  *result,
787                                 DBusError      *error)
788 {
789   DBusMessage *msg;
790   DBusMessage *reply;
791
792   _dbus_return_val_if_fail (connection != NULL, FALSE);
793   _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), FALSE);
794   
795   msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
796                                       DBUS_PATH_ORG_FREEDESKTOP_DBUS,
797                                       DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
798                                       "StartServiceByName");
799
800   if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &name,
801                                  DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID))
802     {
803       dbus_message_unref (msg);
804       _DBUS_SET_OOM (error);
805       return FALSE;
806     }
807
808   reply = dbus_connection_send_with_reply_and_block (connection, msg,
809                                                      -1, error);
810   dbus_message_unref (msg);
811
812   if (reply == NULL)
813     {
814       _DBUS_ASSERT_ERROR_IS_SET (error);
815       return FALSE;
816     }
817
818   if (dbus_set_error_from_message (error, reply))
819     {
820       _DBUS_ASSERT_ERROR_IS_SET (error);
821       dbus_message_unref (reply);
822       return FALSE;
823     }
824
825   if (result != NULL &&
826       !dbus_message_get_args (reply, error, DBUS_TYPE_UINT32,
827                               result, DBUS_TYPE_INVALID))
828     {
829       _DBUS_ASSERT_ERROR_IS_SET (error);
830       dbus_message_unref (reply);
831       return FALSE;
832     }
833   
834   dbus_message_unref (reply);
835   return TRUE;
836 }
837
838 static void
839 send_no_return_values (DBusConnection *connection,
840                        DBusMessage    *msg,
841                        DBusError      *error)
842 {
843   if (error)
844     {
845       /* Block to check success codepath */
846       DBusMessage *reply;
847       
848       reply = dbus_connection_send_with_reply_and_block (connection, msg,
849                                                          -1, error);
850       
851       if (reply == NULL)
852         _DBUS_ASSERT_ERROR_IS_SET (error);
853       else
854         dbus_message_unref (reply);
855     }
856   else
857     {
858       /* Silently-fail nonblocking codepath */
859       dbus_message_set_no_reply (msg, TRUE);
860       dbus_connection_send (connection, msg, NULL);
861     }
862 }
863
864 /**
865  * Adds a match rule to match messages going through the message bus.
866  * The "rule" argument is the string form of a match rule.
867  *
868  * If you pass #NULL for the error, this function will not
869  * block; the match thus won't be added until you flush the
870  * connection, and if there's an error adding the match
871  * (only possible error is lack of resources in the bus),
872  * you won't find out about it.
873  *
874  * If you pass non-#NULL for the error this function will
875  * block until it gets a reply.
876  *
877  * Normal API conventions would have the function return
878  * a boolean value indicating whether the error was set,
879  * but that would require blocking always to determine
880  * the return value.
881  * 
882  * @param connection connection to the message bus
883  * @param rule textual form of match rule
884  * @param error location to store any errors
885  */
886 void
887 dbus_bus_add_match (DBusConnection *connection,
888                     const char     *rule,
889                     DBusError      *error)
890 {
891   DBusMessage *msg;
892
893   _dbus_return_if_fail (rule != NULL);
894
895   msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
896                                       DBUS_PATH_ORG_FREEDESKTOP_DBUS,
897                                       DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
898                                       "AddMatch");
899
900   if (msg == NULL)
901     {
902       _DBUS_SET_OOM (error);
903       return;
904     }
905
906   if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &rule,
907                                  DBUS_TYPE_INVALID))
908     {
909       dbus_message_unref (msg);
910       _DBUS_SET_OOM (error);
911       return;
912     }
913
914   send_no_return_values (connection, msg, error);
915
916   dbus_message_unref (msg);
917 }
918
919 /**
920  * Removes a previously-added match rule "by value" (the most
921  * recently-added identical rule gets removed).  The "rule" argument
922  * is the string form of a match rule.
923  *
924  * If you pass #NULL for the error, this function will not
925  * block; otherwise it will. See detailed explanation in
926  * docs for dbus_bus_add_match().
927  * 
928  * @param connection connection to the message bus
929  * @param rule textual form of match rule
930  * @param error location to store any errors
931  */
932 void
933 dbus_bus_remove_match (DBusConnection *connection,
934                        const char     *rule,
935                        DBusError      *error)
936 {
937   DBusMessage *msg;
938
939   _dbus_return_if_fail (rule != NULL);
940   
941   msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
942                                       DBUS_PATH_ORG_FREEDESKTOP_DBUS,
943                                       DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
944                                       "RemoveMatch");
945
946   if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &rule,
947                                  DBUS_TYPE_INVALID))
948     {
949       dbus_message_unref (msg);
950       _DBUS_SET_OOM (error);
951       return;
952     }
953
954   send_no_return_values (connection, msg, error);
955
956   dbus_message_unref (msg);
957 }
958
959 /** @} */