2005-02-12 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / bus / driver.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* driver.c  Bus client (driver)
3  *
4  * Copyright (C) 2003 CodeFactory AB
5  * Copyright (C) 2003, 2004, 2005 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 "activation.h"
26 #include "connection.h"
27 #include "driver.h"
28 #include "dispatch.h"
29 #include "services.h"
30 #include "signals.h"
31 #include "utils.h"
32 #include <dbus/dbus-string.h>
33 #include <dbus/dbus-internals.h>
34 #include <string.h>
35
36 static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection,
37                                                     DBusMessage    *hello_message,
38                                                     BusTransaction *transaction,
39                                                     DBusError      *error);
40
41 dbus_bool_t
42 bus_driver_send_service_owner_changed (const char     *service_name,
43                                        const char     *old_owner,
44                                        const char     *new_owner,
45                                        BusTransaction *transaction,
46                                        DBusError      *error)
47 {
48   DBusMessage *message;
49   dbus_bool_t retval;
50   const char *null_service;
51
52   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
53
54   null_service = "";
55   _dbus_verbose ("sending name owner changed: %s [%s -> %s]\n",
56                  service_name, 
57                  old_owner ? old_owner : null_service, 
58                  new_owner ? new_owner : null_service);
59
60   message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS,
61                                      DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
62                                      "NameOwnerChanged");
63   
64   if (message == NULL)
65     {
66       BUS_SET_OOM (error);
67       return FALSE;
68     }
69   
70   if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
71     goto oom;
72
73   if (!dbus_message_append_args (message,
74                                  DBUS_TYPE_STRING, &service_name,
75                                  DBUS_TYPE_STRING, old_owner ? &old_owner : &null_service,
76                                  DBUS_TYPE_STRING, new_owner ? &new_owner : &null_service,
77                                  DBUS_TYPE_INVALID))
78     goto oom;
79
80   _dbus_assert (dbus_message_has_signature (message, "sss"));
81   
82   retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
83   dbus_message_unref (message);
84
85   return retval;
86
87  oom:
88   dbus_message_unref (message);
89   BUS_SET_OOM (error);
90   return FALSE;
91 }
92
93 dbus_bool_t
94 bus_driver_send_service_lost (DBusConnection *connection,
95                               const char     *service_name,
96                               BusTransaction *transaction,
97                               DBusError      *error)
98 {
99   DBusMessage *message;
100
101   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
102   
103   message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS,
104                                      DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
105                                      "NameLost");
106   
107   if (message == NULL)
108     {
109       BUS_SET_OOM (error);
110       return FALSE;
111     }
112   
113   if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) ||
114       !dbus_message_append_args (message,
115                                  DBUS_TYPE_STRING, &service_name,
116                                  DBUS_TYPE_INVALID))
117     {
118       dbus_message_unref (message);
119       BUS_SET_OOM (error);
120       return FALSE;
121     }
122
123   if (!bus_transaction_send_from_driver (transaction, connection, message))
124     {
125       dbus_message_unref (message);
126       BUS_SET_OOM (error);
127       return FALSE;
128     }
129   else
130     {
131       dbus_message_unref (message);
132       return TRUE;
133     }
134 }
135
136 dbus_bool_t
137 bus_driver_send_service_acquired (DBusConnection *connection,
138                                   const char     *service_name,
139                                   BusTransaction *transaction,
140                                   DBusError      *error)
141 {
142   DBusMessage *message;
143
144   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
145   
146   message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS,
147                                      DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
148                                      "NameAcquired");
149
150   if (message == NULL)
151     {
152       BUS_SET_OOM (error);
153       return FALSE;
154     }
155   
156   if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) ||
157       !dbus_message_append_args (message,
158                                  DBUS_TYPE_STRING, &service_name,
159                                  DBUS_TYPE_INVALID))
160     {
161       dbus_message_unref (message);
162       BUS_SET_OOM (error);
163       return FALSE;
164     }
165
166   if (!bus_transaction_send_from_driver (transaction, connection, message))
167     {
168       dbus_message_unref (message);
169       BUS_SET_OOM (error);
170       return FALSE;
171     }
172   else
173     {
174       dbus_message_unref (message);
175       return TRUE;
176     }
177 }
178
179 static dbus_bool_t
180 create_unique_client_name (BusRegistry *registry,
181                            DBusString  *str)
182 {
183   /* We never want to use the same unique client name twice, because
184    * we want to guarantee that if you send a message to a given unique
185    * name, you always get the same application. So we use two numbers
186    * for INT_MAX * INT_MAX combinations, should be pretty safe against
187    * wraparound.
188    */
189   /* FIXME these should be in BusRegistry rather than static vars */
190   static int next_major_number = 0;
191   static int next_minor_number = 0;
192   int len;
193   
194   len = _dbus_string_get_length (str);
195   
196   while (TRUE)
197     {
198       /* start out with 1-0, go to 1-1, 1-2, 1-3,
199        * up to 1-MAXINT, then 2-0, 2-1, etc.
200        */
201       if (next_minor_number <= 0)
202         {
203           next_major_number += 1;
204           next_minor_number = 0;
205           if (next_major_number <= 0)
206             _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added");
207         }
208
209       _dbus_assert (next_major_number > 0);
210       _dbus_assert (next_minor_number >= 0);
211
212       /* appname:MAJOR-MINOR */
213       
214       if (!_dbus_string_append (str, ":"))
215         return FALSE;
216       
217       if (!_dbus_string_append_int (str, next_major_number))
218         return FALSE;
219
220       if (!_dbus_string_append (str, "."))
221         return FALSE;
222       
223       if (!_dbus_string_append_int (str, next_minor_number))
224         return FALSE;
225
226       next_minor_number += 1;
227       
228       /* Check if a client with the name exists */
229       if (bus_registry_lookup (registry, str) == NULL)
230         break;
231
232       /* drop the number again, try the next one. */
233       _dbus_string_set_length (str, len);
234     }
235
236   return TRUE;
237 }
238
239 static dbus_bool_t
240 bus_driver_handle_hello (DBusConnection *connection,
241                          BusTransaction *transaction,
242                          DBusMessage    *message,
243                          DBusError      *error)
244 {
245   DBusString unique_name;
246   BusService *service;
247   dbus_bool_t retval;
248   BusRegistry *registry;
249   BusConnections *connections;
250
251   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
252
253   if (bus_connection_is_active (connection))
254     {
255       /* We already handled an Hello message for this connection. */
256       dbus_set_error (error, DBUS_ERROR_FAILED,
257                       "Already handled an Hello message");
258       return FALSE;
259     }
260
261   /* Note that when these limits are exceeded we don't disconnect the
262    * connection; we just sort of leave it hanging there until it times
263    * out or disconnects itself or is dropped due to the max number of
264    * incomplete connections. It's even OK if the connection wants to
265    * retry the hello message, we support that.
266    */
267   connections = bus_connection_get_connections (connection);
268   if (!bus_connections_check_limits (connections, connection,
269                                      error))
270     {
271       _DBUS_ASSERT_ERROR_IS_SET (error);
272       return FALSE;
273     }
274   
275   if (!_dbus_string_init (&unique_name))
276     {
277       BUS_SET_OOM (error);
278       return FALSE;
279     }
280
281   retval = FALSE;
282
283   registry = bus_connection_get_registry (connection);
284   
285   if (!create_unique_client_name (registry, &unique_name))
286     {
287       BUS_SET_OOM (error);
288       goto out_0;
289     }
290
291   if (!bus_connection_complete (connection, &unique_name, error))
292     {
293       _DBUS_ASSERT_ERROR_IS_SET (error);
294       goto out_0;
295     }
296   
297   if (!dbus_message_set_sender (message,
298                                 bus_connection_get_name (connection)))
299     {
300       BUS_SET_OOM (error);
301       goto out_0;
302     }
303   
304   if (!bus_driver_send_welcome_message (connection, message, transaction, error))
305     goto out_0;
306
307   /* Create the service */
308   service = bus_registry_ensure (registry,
309                                  &unique_name, connection, transaction, error);
310   if (service == NULL)
311     goto out_0;
312   
313   bus_service_set_prohibit_replacement (service, TRUE);
314
315   _dbus_assert (bus_connection_is_active (connection));
316   retval = TRUE;
317   
318  out_0:
319   _dbus_string_free (&unique_name);
320   return retval;
321 }
322
323 static dbus_bool_t
324 bus_driver_send_welcome_message (DBusConnection *connection,
325                                  DBusMessage    *hello_message,
326                                  BusTransaction *transaction,
327                                  DBusError      *error)
328 {
329   DBusMessage *welcome;
330   const char *name;
331
332   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
333   
334   name = bus_connection_get_name (connection);
335   _dbus_assert (name != NULL);
336   
337   welcome = dbus_message_new_method_return (hello_message);
338   if (welcome == NULL)
339     {
340       BUS_SET_OOM (error);
341       return FALSE;
342     }
343   
344   if (!dbus_message_append_args (welcome,
345                                  DBUS_TYPE_STRING, &name,
346                                  DBUS_TYPE_INVALID))
347     {
348       dbus_message_unref (welcome);
349       BUS_SET_OOM (error);
350       return FALSE;
351     }
352
353   _dbus_assert (dbus_message_has_signature (welcome, DBUS_TYPE_STRING_AS_STRING));
354   
355   if (!bus_transaction_send_from_driver (transaction, connection, welcome))
356     {
357       dbus_message_unref (welcome);
358       BUS_SET_OOM (error);
359       return FALSE;
360     }
361   else
362     {
363       dbus_message_unref (welcome);
364       return TRUE;
365     }
366 }
367
368 static dbus_bool_t
369 bus_driver_handle_list_services (DBusConnection *connection,
370                                  BusTransaction *transaction,
371                                  DBusMessage    *message,
372                                  DBusError      *error)
373 {
374   DBusMessage *reply;
375   int len;
376   char **services;
377   BusRegistry *registry;
378   int i;
379   DBusMessageIter iter;
380   DBusMessageIter sub;
381
382   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
383   
384   registry = bus_connection_get_registry (connection);
385   
386   reply = dbus_message_new_method_return (message);
387   if (reply == NULL)
388     {
389       BUS_SET_OOM (error);
390       return FALSE;
391     }
392
393   if (!bus_registry_list_services (registry, &services, &len))
394     {
395       dbus_message_unref (reply);
396       BUS_SET_OOM (error);
397       return FALSE;
398     }
399
400   dbus_message_iter_init_append (reply, &iter);
401   
402   if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
403                                          DBUS_TYPE_STRING_AS_STRING,
404                                          &sub))
405     {
406       dbus_free_string_array (services);
407       dbus_message_unref (reply);
408       BUS_SET_OOM (error);
409       return FALSE;
410     }
411
412   i = 0;
413   while (i < len)
414     {
415       if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING,
416                                            &services[i]))
417         {
418           dbus_free_string_array (services);
419           dbus_message_unref (reply);
420           BUS_SET_OOM (error);
421           return FALSE;
422         }
423       ++i;
424     }
425
426   if (!dbus_message_iter_close_container (&iter, &sub))
427     {
428       dbus_free_string_array (services);
429       dbus_message_unref (reply);
430       BUS_SET_OOM (error);
431       return FALSE;
432     }
433   
434   dbus_free_string_array (services);
435   
436   if (!bus_transaction_send_from_driver (transaction, connection, reply))
437     {
438       dbus_message_unref (reply);
439       BUS_SET_OOM (error);
440       return FALSE;
441     }
442   else
443     {
444       dbus_message_unref (reply);
445       return TRUE;
446     }
447 }
448
449 static dbus_bool_t
450 bus_driver_handle_acquire_service (DBusConnection *connection,
451                                    BusTransaction *transaction,
452                                    DBusMessage    *message,
453                                    DBusError      *error)
454 {
455   DBusMessage *reply;
456   DBusString service_name;
457   const char *name;
458   int service_reply;
459   dbus_uint32_t flags;
460   dbus_bool_t retval;
461   BusRegistry *registry;
462
463   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
464   
465   registry = bus_connection_get_registry (connection);
466   
467   if (!dbus_message_get_args (message, error,
468                               DBUS_TYPE_STRING, &name,
469                               DBUS_TYPE_UINT32, &flags,
470                               DBUS_TYPE_INVALID))
471     return FALSE;
472   
473   _dbus_verbose ("Trying to own name %s with flags 0x%x\n", name, flags);
474   
475   retval = FALSE;
476   reply = NULL;
477
478   _dbus_string_init_const (&service_name, name);
479
480   if (!bus_registry_acquire_service (registry, connection,
481                                      &service_name, flags,
482                                      &service_reply, transaction,
483                                      error))
484     goto out;
485   
486   reply = dbus_message_new_method_return (message);
487   if (reply == NULL)
488     {
489       BUS_SET_OOM (error);
490       goto out;
491     }
492
493   if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, &service_reply, DBUS_TYPE_INVALID))
494     {
495       BUS_SET_OOM (error);
496       goto out;
497     }
498
499   if (!bus_transaction_send_from_driver (transaction, connection, reply))
500     {
501       BUS_SET_OOM (error);
502       goto out;
503     }
504
505   retval = TRUE;
506   
507  out:
508   if (reply)
509     dbus_message_unref (reply);
510   return retval;
511
512
513 static dbus_bool_t
514 bus_driver_handle_service_exists (DBusConnection *connection,
515                                   BusTransaction *transaction,
516                                   DBusMessage    *message,
517                                   DBusError      *error)
518 {
519   DBusMessage *reply;
520   DBusString service_name;
521   BusService *service;
522   dbus_bool_t service_exists;
523   const char *name;
524   dbus_bool_t retval;
525   BusRegistry *registry;
526
527   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
528   
529   registry = bus_connection_get_registry (connection);
530   
531   if (!dbus_message_get_args (message, error,
532                               DBUS_TYPE_STRING, &name,
533                               DBUS_TYPE_INVALID))
534     return FALSE;
535
536   retval = FALSE;
537
538   if (strcmp (name, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) == 0)
539     {
540       service_exists = TRUE;
541     }
542   else
543     {
544       _dbus_string_init_const (&service_name, name);
545       service = bus_registry_lookup (registry, &service_name);
546       service_exists = service != NULL;
547     }
548   
549   reply = dbus_message_new_method_return (message);
550   if (reply == NULL)
551     {
552       BUS_SET_OOM (error);
553       goto out;
554     }
555
556   if (!dbus_message_append_args (reply,
557                                  DBUS_TYPE_BOOLEAN, &service_exists,
558                                  0))
559     {
560       BUS_SET_OOM (error);
561       goto out;
562     }
563
564   if (!bus_transaction_send_from_driver (transaction, connection, reply))
565     {
566       BUS_SET_OOM (error);
567       goto out;
568     }
569
570   retval = TRUE;
571   
572  out:
573   if (reply)
574     dbus_message_unref (reply);
575
576   return retval;
577 }
578
579 static dbus_bool_t
580 bus_driver_handle_activate_service (DBusConnection *connection,
581                                     BusTransaction *transaction,
582                                     DBusMessage    *message,
583                                     DBusError      *error)
584 {
585   dbus_uint32_t flags;
586   const char *name;
587   dbus_bool_t retval;
588   BusActivation *activation;
589
590   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
591   
592   activation = bus_connection_get_activation (connection);
593   
594   if (!dbus_message_get_args (message, error,
595                               DBUS_TYPE_STRING, &name,
596                               DBUS_TYPE_UINT32, &flags,
597                               DBUS_TYPE_INVALID))
598     {
599       _DBUS_ASSERT_ERROR_IS_SET (error);
600       _dbus_verbose ("No memory to get arguments to StartServiceByName\n");
601       return FALSE;
602     }
603
604   retval = FALSE;
605
606   if (!bus_activation_activate_service (activation, connection, transaction, FALSE,
607                                         message, name, error))
608     {
609       _DBUS_ASSERT_ERROR_IS_SET (error);
610       _dbus_verbose ("bus_activation_activate_service() failed\n");
611       goto out;
612     }
613
614   retval = TRUE;
615   
616  out:
617   return retval;
618 }
619
620 static dbus_bool_t
621 send_ack_reply (DBusConnection *connection,
622                 BusTransaction *transaction,
623                 DBusMessage    *message,
624                 DBusError      *error)
625 {
626   DBusMessage *reply;
627
628   reply = dbus_message_new_method_return (message);
629   if (reply == NULL)
630     {
631       BUS_SET_OOM (error);
632       return FALSE;
633     }
634
635   if (!bus_transaction_send_from_driver (transaction, connection, reply))
636     {
637       BUS_SET_OOM (error);
638       dbus_message_unref (reply);
639       return FALSE;
640     }
641
642   dbus_message_unref (reply);
643   
644   return TRUE;
645 }
646
647 static dbus_bool_t
648 bus_driver_handle_add_match (DBusConnection *connection,
649                              BusTransaction *transaction,
650                              DBusMessage    *message,
651                              DBusError      *error)
652 {
653   BusMatchRule *rule;
654   const char *text;
655   DBusString str;
656   BusMatchmaker *matchmaker;
657   
658   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
659
660   text = NULL;
661   rule = NULL;
662
663   if (bus_connection_get_n_match_rules (connection) >=
664       bus_context_get_max_match_rules_per_connection (bus_transaction_get_context (transaction)))
665     {
666       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
667                       "Connection \"%s\" is not allowed to add more match rules "
668                       "(increase limits in configuration file if required)",
669                       bus_connection_is_active (connection) ?
670                       bus_connection_get_name (connection) :
671                       "(inactive)");
672       goto failed;
673     }
674   
675   if (!dbus_message_get_args (message, error,
676                               DBUS_TYPE_STRING, &text,
677                               DBUS_TYPE_INVALID))
678     {
679       _dbus_verbose ("No memory to get arguments to AddMatch\n");
680       goto failed;
681     }
682
683   _dbus_string_init_const (&str, text);
684
685   rule = bus_match_rule_parse (connection, &str, error);
686   if (rule == NULL)
687     goto failed;
688
689   matchmaker = bus_connection_get_matchmaker (connection);
690
691   if (!bus_matchmaker_add_rule (matchmaker, rule))
692     {
693       BUS_SET_OOM (error);
694       goto failed;
695     }
696
697   if (!send_ack_reply (connection, transaction,
698                        message, error))
699     {
700       bus_matchmaker_remove_rule (matchmaker, rule);
701       goto failed;
702     }
703   
704   bus_match_rule_unref (rule);
705   
706   return TRUE;
707
708  failed:
709   _DBUS_ASSERT_ERROR_IS_SET (error);
710   if (rule)
711     bus_match_rule_unref (rule);
712   return FALSE;
713 }
714
715 static dbus_bool_t
716 bus_driver_handle_remove_match (DBusConnection *connection,
717                                 BusTransaction *transaction,
718                                 DBusMessage    *message,
719                                 DBusError      *error)
720 {
721   BusMatchRule *rule;
722   const char *text;
723   DBusString str;
724   BusMatchmaker *matchmaker;
725   
726   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
727
728   text = NULL;
729   rule = NULL;
730   
731   if (!dbus_message_get_args (message, error,
732                               DBUS_TYPE_STRING, &text,
733                               DBUS_TYPE_INVALID))
734     {
735       _dbus_verbose ("No memory to get arguments to RemoveMatch\n");
736       goto failed;
737     }
738
739   _dbus_string_init_const (&str, text);
740
741   rule = bus_match_rule_parse (connection, &str, error);
742   if (rule == NULL)
743     goto failed;
744
745   /* Send the ack before we remove the rule, since the ack is undone
746    * on transaction cancel, but rule removal isn't.
747    */
748   if (!send_ack_reply (connection, transaction,
749                        message, error))
750     goto failed;
751   
752   matchmaker = bus_connection_get_matchmaker (connection);
753
754   if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error))
755     goto failed;
756
757   bus_match_rule_unref (rule);
758   
759   return TRUE;
760
761  failed:
762   _DBUS_ASSERT_ERROR_IS_SET (error);
763   if (rule)
764     bus_match_rule_unref (rule);
765   return FALSE;
766 }
767
768 static dbus_bool_t
769 bus_driver_handle_get_service_owner (DBusConnection *connection,
770                                      BusTransaction *transaction,
771                                      DBusMessage    *message,
772                                      DBusError      *error)
773 {
774   const char *text;
775   const char *base_name;
776   DBusString str;
777   BusRegistry *registry;
778   BusService *service;
779   DBusMessage *reply;
780   
781   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
782
783   registry = bus_connection_get_registry (connection);
784
785   text = NULL;
786   reply = NULL;
787
788   if (! dbus_message_get_args (message, error,
789                                DBUS_TYPE_STRING, &text,
790                                DBUS_TYPE_INVALID))
791       goto failed;
792
793   _dbus_string_init_const (&str, text);
794   service = bus_registry_lookup (registry, &str);
795   if (service == NULL &&
796       _dbus_string_equal_c_str (&str, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
797     {
798       /* ORG_FREEDESKTOP_DBUS owns itself */
799       base_name = DBUS_SERVICE_ORG_FREEDESKTOP_DBUS;
800     }
801   else if (service == NULL)
802     {
803       dbus_set_error (error, 
804                       DBUS_ERROR_NAME_HAS_NO_OWNER,
805                       "Could not get owner of name '%s': no such name", text);
806       goto failed;
807     }
808   else
809     {
810       base_name = bus_connection_get_name (bus_service_get_primary_owner (service));
811       if (base_name == NULL)
812         {
813           /* FIXME - how is this error possible? */
814           dbus_set_error (error,
815                           DBUS_ERROR_FAILED,
816                           "Could not determine unique name for '%s'", text);
817           goto failed;
818         }
819       _dbus_assert (*base_name == ':');      
820     }
821
822   _dbus_assert (base_name != NULL);
823
824   reply = dbus_message_new_method_return (message);
825   if (reply == NULL)
826     goto oom;
827
828   if (! dbus_message_append_args (reply, 
829                                   DBUS_TYPE_STRING, &base_name,
830                                   DBUS_TYPE_INVALID))
831     goto oom;
832   
833   if (! bus_transaction_send_from_driver (transaction, connection, reply))
834     goto oom;
835
836   dbus_message_unref (reply);
837
838   return TRUE;
839
840  oom:
841   BUS_SET_OOM (error);
842
843  failed:
844   _DBUS_ASSERT_ERROR_IS_SET (error);
845   if (reply)
846     dbus_message_unref (reply);
847   return FALSE;
848 }
849
850 static dbus_bool_t
851 bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
852                                             BusTransaction *transaction,
853                                             DBusMessage    *message,
854                                             DBusError      *error)
855 {
856   const char *service;
857   DBusString str;
858   BusRegistry *registry;
859   BusService *serv;
860   DBusConnection *conn;
861   DBusMessage *reply;
862   unsigned long uid;
863   dbus_uint32_t uid32;
864
865   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
866
867   registry = bus_connection_get_registry (connection);
868
869   service = NULL;
870   reply = NULL;
871
872   if (! dbus_message_get_args (message, error,
873                                DBUS_TYPE_STRING, &service,
874                                DBUS_TYPE_INVALID))
875       goto failed;
876
877   _dbus_verbose ("asked for UID of connection %s\n", service);
878
879   _dbus_string_init_const (&str, service);
880   serv = bus_registry_lookup (registry, &str);
881   if (serv == NULL)
882     {
883       dbus_set_error (error, 
884                       DBUS_ERROR_NAME_HAS_NO_OWNER,
885                       "Could not get UID of name '%s': no such name", service);
886       goto failed;
887     }
888
889   conn = bus_service_get_primary_owner (serv);
890
891   reply = dbus_message_new_method_return (message);
892   if (reply == NULL)
893     goto oom;
894
895   if (!dbus_connection_get_unix_user (conn, &uid))
896     {
897       dbus_set_error (error,
898                       DBUS_ERROR_FAILED,
899                       "Could not determine UID for '%s'", service);
900       goto failed;
901     }
902
903   uid32 = uid;
904   if (! dbus_message_append_args (reply,
905                                   DBUS_TYPE_UINT32, &uid32,
906                                   DBUS_TYPE_INVALID))
907     goto oom;
908
909   if (! bus_transaction_send_from_driver (transaction, connection, reply))
910     goto oom;
911
912   dbus_message_unref (reply);
913
914   return TRUE;
915
916  oom:
917   BUS_SET_OOM (error);
918
919  failed:
920   _DBUS_ASSERT_ERROR_IS_SET (error);
921   if (reply)
922     dbus_message_unref (reply);
923   return FALSE;
924 }
925
926 static dbus_bool_t
927 bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
928                                                   BusTransaction *transaction,
929                                                   DBusMessage    *message,
930                                                   DBusError      *error)
931 {
932   const char *service;
933   DBusString str;
934   BusRegistry *registry;
935   BusService *serv;
936   DBusConnection *conn;
937   DBusMessage *reply;
938   unsigned long pid;
939   dbus_uint32_t pid32;
940
941   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
942
943   registry = bus_connection_get_registry (connection);
944
945   service = NULL;
946   reply = NULL;
947
948   if (! dbus_message_get_args (message, error,
949                                DBUS_TYPE_STRING, &service,
950                                DBUS_TYPE_INVALID))
951       goto failed;
952
953   _dbus_verbose ("asked for PID of connection %s\n", service);
954
955   _dbus_string_init_const (&str, service);
956   serv = bus_registry_lookup (registry, &str);
957   if (serv == NULL)
958     {
959       dbus_set_error (error, 
960                       DBUS_ERROR_NAME_HAS_NO_OWNER,
961                       "Could not get PID of name '%s': no such name", service);
962       goto failed;
963     }
964
965   conn = bus_service_get_primary_owner (serv);
966
967   reply = dbus_message_new_method_return (message);
968   if (reply == NULL)
969     goto oom;
970
971   if (!dbus_connection_get_unix_process_id (conn, &pid))
972     {
973       dbus_set_error (error,
974                       DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN,
975                       "Could not determine PID for '%s'", service);
976       goto failed;
977     }
978
979   pid32 = pid;
980   if (! dbus_message_append_args (reply,
981                                   DBUS_TYPE_UINT32, &pid32,
982                                   DBUS_TYPE_INVALID))
983     goto oom;
984
985   if (! bus_transaction_send_from_driver (transaction, connection, reply))
986     goto oom;
987
988   dbus_message_unref (reply);
989
990   return TRUE;
991
992  oom:
993   BUS_SET_OOM (error);
994
995  failed:
996   _DBUS_ASSERT_ERROR_IS_SET (error);
997   if (reply)
998     dbus_message_unref (reply);
999   return FALSE;
1000 }
1001
1002 static dbus_bool_t
1003 bus_driver_handle_reload_config (DBusConnection *connection,
1004                                  BusTransaction *transaction,
1005                                  DBusMessage    *message,
1006                                  DBusError      *error)
1007 {
1008   BusContext *context;
1009   dbus_bool_t retval;
1010
1011   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1012
1013   retval = FALSE;
1014
1015   context = bus_connection_get_context (connection);
1016   if (!bus_context_reload_config (context, error))
1017     {
1018       _DBUS_ASSERT_ERROR_IS_SET (error);
1019       goto out;
1020     }
1021
1022   retval = TRUE;
1023   
1024  out:
1025   return retval;
1026 }
1027
1028 /* For speed it might be useful to sort this in order of
1029  * frequency of use (but doesn't matter with only a few items
1030  * anyhow)
1031  */
1032 struct
1033 {
1034   const char *name;
1035   const char *in_args;
1036   const char *out_args;
1037   dbus_bool_t (* handler) (DBusConnection *connection,
1038                            BusTransaction *transaction,
1039                            DBusMessage    *message,
1040                            DBusError      *error);
1041 } message_handlers[] = {
1042   { "RequestName",
1043     DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
1044     DBUS_TYPE_UINT32_AS_STRING,
1045     bus_driver_handle_acquire_service },
1046   { "StartServiceByName",
1047     DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
1048     DBUS_TYPE_UINT32_AS_STRING,
1049     bus_driver_handle_activate_service },
1050   { "Hello",
1051     "",
1052     DBUS_TYPE_STRING_AS_STRING,
1053     bus_driver_handle_hello },
1054   { "NameHasOwner",
1055     DBUS_TYPE_STRING_AS_STRING,
1056     DBUS_TYPE_BOOLEAN_AS_STRING,
1057     bus_driver_handle_service_exists },
1058   { "ListNames",
1059     "",
1060     DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
1061     bus_driver_handle_list_services },
1062   { "AddMatch",
1063     DBUS_TYPE_STRING_AS_STRING,
1064     "",
1065     bus_driver_handle_add_match },
1066   { "RemoveMatch",
1067     DBUS_TYPE_STRING_AS_STRING,
1068     "",
1069     bus_driver_handle_remove_match },
1070   { "GetNameOwner",
1071     DBUS_TYPE_STRING_AS_STRING,
1072     DBUS_TYPE_STRING_AS_STRING,
1073     bus_driver_handle_get_service_owner },
1074   { "GetConnectionUnixUser",
1075     DBUS_TYPE_STRING_AS_STRING,
1076     DBUS_TYPE_UINT32_AS_STRING,
1077     bus_driver_handle_get_connection_unix_user },
1078   { "GetConnectionUnixProcessID",
1079     DBUS_TYPE_STRING_AS_STRING,
1080     DBUS_TYPE_UINT32_AS_STRING,
1081     bus_driver_handle_get_connection_unix_process_id },
1082   { "ReloadConfig",
1083     "",
1084     "",
1085     bus_driver_handle_reload_config }
1086 };
1087
1088 static dbus_bool_t
1089 bus_driver_handle_introspect (DBusConnection *connection,
1090                               BusTransaction *transaction,
1091                               DBusMessage    *message,
1092                               DBusError      *error)
1093 {
1094   DBusString xml;
1095   DBusMessage *reply;
1096   const char *v_STRING;
1097   int i;
1098
1099   _dbus_verbose ("Introspect() on bus driver\n");
1100   
1101   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1102
1103   reply = NULL;
1104
1105   if (! dbus_message_get_args (message, error,
1106                                DBUS_TYPE_INVALID))
1107     {
1108       _DBUS_ASSERT_ERROR_IS_SET (error);
1109       return FALSE;
1110     }
1111
1112   if (!_dbus_string_init (&xml))
1113     {
1114       BUS_SET_OOM (error);
1115       return FALSE;
1116     }
1117
1118   if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE))
1119     goto oom;
1120   if (!_dbus_string_append (&xml, "<node>\n"))
1121     goto oom;
1122   if (!_dbus_string_append (&xml, "  <interface name=\"org.freedesktop.Introspectable\">\n"))
1123     goto oom;
1124   if (!_dbus_string_append (&xml, "    <method name=\"Introspect\">\n"))
1125     goto oom;
1126   if (!_dbus_string_append (&xml, "      <arg name=\"data\" direction=\"out\" type=\"string\"/>\n"))
1127     goto oom;
1128   if (!_dbus_string_append (&xml, "    </method>\n"))
1129     goto oom;
1130   if (!_dbus_string_append (&xml, "  </interface>\n"))
1131     goto oom;
1132
1133   if (!_dbus_string_append_printf (&xml, "  <interface name=\"%s\">\n",
1134                                    DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS))
1135     goto oom;
1136
1137   i = 0;
1138   while (i < _DBUS_N_ELEMENTS (message_handlers))
1139     {
1140       if (!_dbus_string_append_printf (&xml, "    <method name=\"%s\">\n",
1141                                        message_handlers[i].name))
1142         goto oom;
1143
1144       /* This hacky mess can probably get mopped up eventually when the
1145        * introspection format is related to the signature format
1146        */
1147       
1148       if (strcmp (message_handlers[i].in_args, "") == 0)
1149         ;
1150       else if (strcmp (message_handlers[i].in_args,
1151                        DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING) == 0)
1152         {
1153           if (!_dbus_string_append (&xml, "      <arg direction=\"in\" type=\"string\"/>\n"))
1154             goto oom;
1155           if (!_dbus_string_append (&xml, "      <arg direction=\"in\" type=\"uint32\"/>\n"))
1156             goto oom;
1157         }
1158       else if (strcmp (message_handlers[i].in_args,
1159                        DBUS_TYPE_STRING_AS_STRING) == 0)
1160         {
1161           if (!_dbus_string_append (&xml, "      <arg direction=\"in\" type=\"string\"/>\n"))
1162             goto oom;
1163         }
1164       else
1165         {
1166           _dbus_warn ("Lack introspection code for in sig '%s'\n",
1167                       message_handlers[i].in_args);
1168           _dbus_assert_not_reached ("FIXME introspection missing");
1169         }
1170
1171       if (strcmp (message_handlers[i].out_args, "") == 0)
1172         ;
1173       else if (strcmp (message_handlers[i].out_args,
1174                        DBUS_TYPE_STRING_AS_STRING) == 0)
1175         {
1176           if (!_dbus_string_append (&xml, "      <arg direction=\"out\" type=\"string\"/>\n"))
1177             goto oom;
1178         }
1179       else if (strcmp (message_handlers[i].out_args,
1180                        DBUS_TYPE_BOOLEAN_AS_STRING) == 0)
1181         {
1182           if (!_dbus_string_append (&xml, "      <arg direction=\"out\" type=\"boolean\"/>\n"))
1183             goto oom;
1184         }
1185       else if (strcmp (message_handlers[i].out_args,
1186                        DBUS_TYPE_UINT32_AS_STRING) == 0)
1187         {
1188           if (!_dbus_string_append (&xml, "      <arg direction=\"out\" type=\"uint32\"/>\n"))
1189             goto oom;
1190         }
1191       else if (strcmp (message_handlers[i].out_args,
1192                        DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING) == 0)
1193         {
1194           /* FIXME introspection format doesn't handle arrays yet */
1195           if (!_dbus_string_append (&xml, "      <arg direction=\"out\" type=\"string\"/>\n"))
1196             goto oom;
1197         }
1198       else
1199         {
1200           _dbus_warn ("Lack introspection code for out sig '%s'\n",
1201                       message_handlers[i].out_args);
1202           _dbus_assert_not_reached ("FIXME introspection missing");
1203         }
1204       
1205       if (!_dbus_string_append (&xml, "    </method>\n"))
1206         goto oom;
1207       
1208       ++i;
1209     }
1210   
1211   if (!_dbus_string_append (&xml, "  </interface>\n"))
1212     goto oom;
1213   
1214   if (!_dbus_string_append (&xml, "</node>\n"))
1215     goto oom;
1216
1217   reply = dbus_message_new_method_return (message);
1218   if (reply == NULL)
1219     goto oom;
1220
1221   v_STRING = _dbus_string_get_const_data (&xml);
1222   if (! dbus_message_append_args (reply,
1223                                   DBUS_TYPE_STRING, &v_STRING,
1224                                   DBUS_TYPE_INVALID))
1225     goto oom;
1226
1227   if (! bus_transaction_send_from_driver (transaction, connection, reply))
1228     goto oom;
1229
1230   dbus_message_unref (reply);
1231   _dbus_string_free (&xml);
1232
1233   return TRUE;
1234
1235  oom:
1236   BUS_SET_OOM (error);
1237
1238   if (reply)
1239     dbus_message_unref (reply);
1240
1241   _dbus_string_free (&xml);
1242   
1243   return FALSE;
1244 }
1245
1246 dbus_bool_t
1247 bus_driver_handle_message (DBusConnection *connection,
1248                            BusTransaction *transaction,
1249                            DBusMessage    *message,
1250                            DBusError      *error)
1251 {
1252   const char *name, *sender, *interface;
1253   int i;
1254
1255   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1256
1257   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
1258     {
1259       _dbus_verbose ("Driver got a non-method-call message, ignoring\n");
1260       return TRUE; /* we just ignore this */
1261     }
1262
1263   if (dbus_message_is_method_call (message,
1264                                    DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE,
1265                                    "Introspect"))
1266     return bus_driver_handle_introspect (connection, transaction, message, error);
1267   
1268   interface = dbus_message_get_interface (message);
1269   if (interface == NULL)
1270     interface = DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS;
1271   
1272   _dbus_assert (dbus_message_get_member (message) != NULL);
1273   
1274   name = dbus_message_get_member (message);
1275   sender = dbus_message_get_sender (message);
1276   
1277   if (strcmp (interface,
1278               DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS) != 0)
1279     {
1280       _dbus_verbose ("Driver got message to unknown interface \"%s\"\n",
1281                      interface);
1282       goto unknown;
1283     }
1284   
1285   _dbus_verbose ("Driver got a method call: %s\n",
1286                  dbus_message_get_member (message));
1287   
1288   /* security checks should have kept this from getting here */
1289   _dbus_assert (sender != NULL || strcmp (name, "Hello") == 0);
1290   
1291   i = 0;
1292   while (i < _DBUS_N_ELEMENTS (message_handlers))
1293     {
1294       if (strcmp (message_handlers[i].name, name) == 0)
1295         {
1296           _dbus_verbose ("Found driver handler for %s\n", name);
1297
1298           if (!dbus_message_has_signature (message, message_handlers[i].in_args))
1299             {
1300               _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1301               _dbus_verbose ("Call to %s has wrong args (%s, expected %s)\n",
1302                              name, dbus_message_get_signature (message),
1303                              message_handlers[i].in_args);
1304               
1305               dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
1306                               "Call to %s has wrong args (%s, expected %s)\n",
1307                               name, dbus_message_get_signature (message),
1308                               message_handlers[i].in_args);
1309               _DBUS_ASSERT_ERROR_IS_SET (error);
1310               return FALSE;
1311             }
1312           
1313           if ((* message_handlers[i].handler) (connection, transaction, message, error))
1314             {
1315               _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1316               _dbus_verbose ("Driver handler succeeded\n");
1317               return TRUE;
1318             }
1319           else
1320             {
1321               _DBUS_ASSERT_ERROR_IS_SET (error);
1322               _dbus_verbose ("Driver handler returned failure\n");
1323               return FALSE;
1324             }
1325         }
1326       
1327       ++i;
1328     }
1329
1330  unknown:
1331   _dbus_verbose ("No driver handler for message \"%s\"\n",
1332                  name);
1333
1334   dbus_set_error (error, DBUS_ERROR_UNKNOWN_METHOD,
1335                   "%s does not understand message %s",
1336                   DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, name);
1337   
1338   return FALSE;
1339 }
1340
1341 void
1342 bus_driver_remove_connection (DBusConnection *connection)
1343 {
1344   /* FIXME Does nothing for now, should unregister the connection
1345    * with the bus driver.
1346    */
1347 }