2005-03-11 Colin Walters <walters@verbum.org>
[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_DBUS,
61                                      DBUS_INTERFACE_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_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_DBUS,
104                                      DBUS_INTERFACE_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_DBUS,
147                                      DBUS_INTERFACE_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   {
413     /* Include the bus driver in the list */
414     const char *v_STRING = DBUS_SERVICE_DBUS;
415     if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING,
416                                          &v_STRING))
417       {
418         dbus_free_string_array (services);
419         dbus_message_unref (reply);
420         BUS_SET_OOM (error);
421         return FALSE;
422       }
423   }
424   
425   i = 0;
426   while (i < len)
427     {
428       if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING,
429                                            &services[i]))
430         {
431           dbus_free_string_array (services);
432           dbus_message_unref (reply);
433           BUS_SET_OOM (error);
434           return FALSE;
435         }
436       ++i;
437     }
438
439   if (!dbus_message_iter_close_container (&iter, &sub))
440     {
441       dbus_free_string_array (services);
442       dbus_message_unref (reply);
443       BUS_SET_OOM (error);
444       return FALSE;
445     }
446   
447   dbus_free_string_array (services);
448   
449   if (!bus_transaction_send_from_driver (transaction, connection, reply))
450     {
451       dbus_message_unref (reply);
452       BUS_SET_OOM (error);
453       return FALSE;
454     }
455   else
456     {
457       dbus_message_unref (reply);
458       return TRUE;
459     }
460 }
461
462 static dbus_bool_t
463 bus_driver_handle_acquire_service (DBusConnection *connection,
464                                    BusTransaction *transaction,
465                                    DBusMessage    *message,
466                                    DBusError      *error)
467 {
468   DBusMessage *reply;
469   DBusString service_name;
470   const char *name;
471   int service_reply;
472   dbus_uint32_t flags;
473   dbus_bool_t retval;
474   BusRegistry *registry;
475
476   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
477   
478   registry = bus_connection_get_registry (connection);
479   
480   if (!dbus_message_get_args (message, error,
481                               DBUS_TYPE_STRING, &name,
482                               DBUS_TYPE_UINT32, &flags,
483                               DBUS_TYPE_INVALID))
484     return FALSE;
485   
486   _dbus_verbose ("Trying to own name %s with flags 0x%x\n", name, flags);
487   
488   retval = FALSE;
489   reply = NULL;
490
491   _dbus_string_init_const (&service_name, name);
492
493   if (!bus_registry_acquire_service (registry, connection,
494                                      &service_name, flags,
495                                      &service_reply, transaction,
496                                      error))
497     goto out;
498   
499   reply = dbus_message_new_method_return (message);
500   if (reply == NULL)
501     {
502       BUS_SET_OOM (error);
503       goto out;
504     }
505
506   if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, &service_reply, DBUS_TYPE_INVALID))
507     {
508       BUS_SET_OOM (error);
509       goto out;
510     }
511
512   if (!bus_transaction_send_from_driver (transaction, connection, reply))
513     {
514       BUS_SET_OOM (error);
515       goto out;
516     }
517
518   retval = TRUE;
519   
520  out:
521   if (reply)
522     dbus_message_unref (reply);
523   return retval;
524
525
526 static dbus_bool_t
527 bus_driver_handle_service_exists (DBusConnection *connection,
528                                   BusTransaction *transaction,
529                                   DBusMessage    *message,
530                                   DBusError      *error)
531 {
532   DBusMessage *reply;
533   DBusString service_name;
534   BusService *service;
535   dbus_bool_t service_exists;
536   const char *name;
537   dbus_bool_t retval;
538   BusRegistry *registry;
539
540   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
541   
542   registry = bus_connection_get_registry (connection);
543   
544   if (!dbus_message_get_args (message, error,
545                               DBUS_TYPE_STRING, &name,
546                               DBUS_TYPE_INVALID))
547     return FALSE;
548
549   retval = FALSE;
550
551   if (strcmp (name, DBUS_SERVICE_DBUS) == 0)
552     {
553       service_exists = TRUE;
554     }
555   else
556     {
557       _dbus_string_init_const (&service_name, name);
558       service = bus_registry_lookup (registry, &service_name);
559       service_exists = service != NULL;
560     }
561   
562   reply = dbus_message_new_method_return (message);
563   if (reply == NULL)
564     {
565       BUS_SET_OOM (error);
566       goto out;
567     }
568
569   if (!dbus_message_append_args (reply,
570                                  DBUS_TYPE_BOOLEAN, &service_exists,
571                                  0))
572     {
573       BUS_SET_OOM (error);
574       goto out;
575     }
576
577   if (!bus_transaction_send_from_driver (transaction, connection, reply))
578     {
579       BUS_SET_OOM (error);
580       goto out;
581     }
582
583   retval = TRUE;
584   
585  out:
586   if (reply)
587     dbus_message_unref (reply);
588
589   return retval;
590 }
591
592 static dbus_bool_t
593 bus_driver_handle_activate_service (DBusConnection *connection,
594                                     BusTransaction *transaction,
595                                     DBusMessage    *message,
596                                     DBusError      *error)
597 {
598   dbus_uint32_t flags;
599   const char *name;
600   dbus_bool_t retval;
601   BusActivation *activation;
602
603   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
604   
605   activation = bus_connection_get_activation (connection);
606   
607   if (!dbus_message_get_args (message, error,
608                               DBUS_TYPE_STRING, &name,
609                               DBUS_TYPE_UINT32, &flags,
610                               DBUS_TYPE_INVALID))
611     {
612       _DBUS_ASSERT_ERROR_IS_SET (error);
613       _dbus_verbose ("No memory to get arguments to StartServiceByName\n");
614       return FALSE;
615     }
616
617   retval = FALSE;
618
619   if (!bus_activation_activate_service (activation, connection, transaction, FALSE,
620                                         message, name, error))
621     {
622       _DBUS_ASSERT_ERROR_IS_SET (error);
623       _dbus_verbose ("bus_activation_activate_service() failed\n");
624       goto out;
625     }
626
627   retval = TRUE;
628   
629  out:
630   return retval;
631 }
632
633 static dbus_bool_t
634 send_ack_reply (DBusConnection *connection,
635                 BusTransaction *transaction,
636                 DBusMessage    *message,
637                 DBusError      *error)
638 {
639   DBusMessage *reply;
640
641   reply = dbus_message_new_method_return (message);
642   if (reply == NULL)
643     {
644       BUS_SET_OOM (error);
645       return FALSE;
646     }
647
648   if (!bus_transaction_send_from_driver (transaction, connection, reply))
649     {
650       BUS_SET_OOM (error);
651       dbus_message_unref (reply);
652       return FALSE;
653     }
654
655   dbus_message_unref (reply);
656   
657   return TRUE;
658 }
659
660 static dbus_bool_t
661 bus_driver_handle_add_match (DBusConnection *connection,
662                              BusTransaction *transaction,
663                              DBusMessage    *message,
664                              DBusError      *error)
665 {
666   BusMatchRule *rule;
667   const char *text;
668   DBusString str;
669   BusMatchmaker *matchmaker;
670   
671   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
672
673   text = NULL;
674   rule = NULL;
675
676   if (bus_connection_get_n_match_rules (connection) >=
677       bus_context_get_max_match_rules_per_connection (bus_transaction_get_context (transaction)))
678     {
679       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
680                       "Connection \"%s\" is not allowed to add more match rules "
681                       "(increase limits in configuration file if required)",
682                       bus_connection_is_active (connection) ?
683                       bus_connection_get_name (connection) :
684                       "(inactive)");
685       goto failed;
686     }
687   
688   if (!dbus_message_get_args (message, error,
689                               DBUS_TYPE_STRING, &text,
690                               DBUS_TYPE_INVALID))
691     {
692       _dbus_verbose ("No memory to get arguments to AddMatch\n");
693       goto failed;
694     }
695
696   _dbus_string_init_const (&str, text);
697
698   rule = bus_match_rule_parse (connection, &str, error);
699   if (rule == NULL)
700     goto failed;
701
702   matchmaker = bus_connection_get_matchmaker (connection);
703
704   if (!bus_matchmaker_add_rule (matchmaker, rule))
705     {
706       BUS_SET_OOM (error);
707       goto failed;
708     }
709
710   if (!send_ack_reply (connection, transaction,
711                        message, error))
712     {
713       bus_matchmaker_remove_rule (matchmaker, rule);
714       goto failed;
715     }
716   
717   bus_match_rule_unref (rule);
718   
719   return TRUE;
720
721  failed:
722   _DBUS_ASSERT_ERROR_IS_SET (error);
723   if (rule)
724     bus_match_rule_unref (rule);
725   return FALSE;
726 }
727
728 static dbus_bool_t
729 bus_driver_handle_remove_match (DBusConnection *connection,
730                                 BusTransaction *transaction,
731                                 DBusMessage    *message,
732                                 DBusError      *error)
733 {
734   BusMatchRule *rule;
735   const char *text;
736   DBusString str;
737   BusMatchmaker *matchmaker;
738   
739   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
740
741   text = NULL;
742   rule = NULL;
743   
744   if (!dbus_message_get_args (message, error,
745                               DBUS_TYPE_STRING, &text,
746                               DBUS_TYPE_INVALID))
747     {
748       _dbus_verbose ("No memory to get arguments to RemoveMatch\n");
749       goto failed;
750     }
751
752   _dbus_string_init_const (&str, text);
753
754   rule = bus_match_rule_parse (connection, &str, error);
755   if (rule == NULL)
756     goto failed;
757
758   /* Send the ack before we remove the rule, since the ack is undone
759    * on transaction cancel, but rule removal isn't.
760    */
761   if (!send_ack_reply (connection, transaction,
762                        message, error))
763     goto failed;
764   
765   matchmaker = bus_connection_get_matchmaker (connection);
766
767   if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error))
768     goto failed;
769
770   bus_match_rule_unref (rule);
771   
772   return TRUE;
773
774  failed:
775   _DBUS_ASSERT_ERROR_IS_SET (error);
776   if (rule)
777     bus_match_rule_unref (rule);
778   return FALSE;
779 }
780
781 static dbus_bool_t
782 bus_driver_handle_get_service_owner (DBusConnection *connection,
783                                      BusTransaction *transaction,
784                                      DBusMessage    *message,
785                                      DBusError      *error)
786 {
787   const char *text;
788   const char *base_name;
789   DBusString str;
790   BusRegistry *registry;
791   BusService *service;
792   DBusMessage *reply;
793   
794   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
795
796   registry = bus_connection_get_registry (connection);
797
798   text = NULL;
799   reply = NULL;
800
801   if (! dbus_message_get_args (message, error,
802                                DBUS_TYPE_STRING, &text,
803                                DBUS_TYPE_INVALID))
804       goto failed;
805
806   _dbus_string_init_const (&str, text);
807   service = bus_registry_lookup (registry, &str);
808   if (service == NULL &&
809       _dbus_string_equal_c_str (&str, DBUS_SERVICE_DBUS))
810     {
811       /* ORG_FREEDESKTOP_DBUS owns itself */
812       base_name = DBUS_SERVICE_DBUS;
813     }
814   else if (service == NULL)
815     {
816       dbus_set_error (error, 
817                       DBUS_ERROR_NAME_HAS_NO_OWNER,
818                       "Could not get owner of name '%s': no such name", text);
819       goto failed;
820     }
821   else
822     {
823       base_name = bus_connection_get_name (bus_service_get_primary_owner (service));
824       if (base_name == NULL)
825         {
826           /* FIXME - how is this error possible? */
827           dbus_set_error (error,
828                           DBUS_ERROR_FAILED,
829                           "Could not determine unique name for '%s'", text);
830           goto failed;
831         }
832       _dbus_assert (*base_name == ':');      
833     }
834
835   _dbus_assert (base_name != NULL);
836
837   reply = dbus_message_new_method_return (message);
838   if (reply == NULL)
839     goto oom;
840
841   if (! dbus_message_append_args (reply, 
842                                   DBUS_TYPE_STRING, &base_name,
843                                   DBUS_TYPE_INVALID))
844     goto oom;
845   
846   if (! bus_transaction_send_from_driver (transaction, connection, reply))
847     goto oom;
848
849   dbus_message_unref (reply);
850
851   return TRUE;
852
853  oom:
854   BUS_SET_OOM (error);
855
856  failed:
857   _DBUS_ASSERT_ERROR_IS_SET (error);
858   if (reply)
859     dbus_message_unref (reply);
860   return FALSE;
861 }
862
863 static dbus_bool_t
864 bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
865                                             BusTransaction *transaction,
866                                             DBusMessage    *message,
867                                             DBusError      *error)
868 {
869   const char *service;
870   DBusString str;
871   BusRegistry *registry;
872   BusService *serv;
873   DBusConnection *conn;
874   DBusMessage *reply;
875   unsigned long uid;
876   dbus_uint32_t uid32;
877
878   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
879
880   registry = bus_connection_get_registry (connection);
881
882   service = NULL;
883   reply = NULL;
884
885   if (! dbus_message_get_args (message, error,
886                                DBUS_TYPE_STRING, &service,
887                                DBUS_TYPE_INVALID))
888       goto failed;
889
890   _dbus_verbose ("asked for UID of connection %s\n", service);
891
892   _dbus_string_init_const (&str, service);
893   serv = bus_registry_lookup (registry, &str);
894   if (serv == NULL)
895     {
896       dbus_set_error (error, 
897                       DBUS_ERROR_NAME_HAS_NO_OWNER,
898                       "Could not get UID of name '%s': no such name", service);
899       goto failed;
900     }
901
902   conn = bus_service_get_primary_owner (serv);
903
904   reply = dbus_message_new_method_return (message);
905   if (reply == NULL)
906     goto oom;
907
908   if (!dbus_connection_get_unix_user (conn, &uid))
909     {
910       dbus_set_error (error,
911                       DBUS_ERROR_FAILED,
912                       "Could not determine UID for '%s'", service);
913       goto failed;
914     }
915
916   uid32 = uid;
917   if (! dbus_message_append_args (reply,
918                                   DBUS_TYPE_UINT32, &uid32,
919                                   DBUS_TYPE_INVALID))
920     goto oom;
921
922   if (! bus_transaction_send_from_driver (transaction, connection, reply))
923     goto oom;
924
925   dbus_message_unref (reply);
926
927   return TRUE;
928
929  oom:
930   BUS_SET_OOM (error);
931
932  failed:
933   _DBUS_ASSERT_ERROR_IS_SET (error);
934   if (reply)
935     dbus_message_unref (reply);
936   return FALSE;
937 }
938
939 static dbus_bool_t
940 bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
941                                                   BusTransaction *transaction,
942                                                   DBusMessage    *message,
943                                                   DBusError      *error)
944 {
945   const char *service;
946   DBusString str;
947   BusRegistry *registry;
948   BusService *serv;
949   DBusConnection *conn;
950   DBusMessage *reply;
951   unsigned long pid;
952   dbus_uint32_t pid32;
953
954   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
955
956   registry = bus_connection_get_registry (connection);
957
958   service = NULL;
959   reply = NULL;
960
961   if (! dbus_message_get_args (message, error,
962                                DBUS_TYPE_STRING, &service,
963                                DBUS_TYPE_INVALID))
964       goto failed;
965
966   _dbus_verbose ("asked for PID of connection %s\n", service);
967
968   _dbus_string_init_const (&str, service);
969   serv = bus_registry_lookup (registry, &str);
970   if (serv == NULL)
971     {
972       dbus_set_error (error, 
973                       DBUS_ERROR_NAME_HAS_NO_OWNER,
974                       "Could not get PID of name '%s': no such name", service);
975       goto failed;
976     }
977
978   conn = bus_service_get_primary_owner (serv);
979
980   reply = dbus_message_new_method_return (message);
981   if (reply == NULL)
982     goto oom;
983
984   if (!dbus_connection_get_unix_process_id (conn, &pid))
985     {
986       dbus_set_error (error,
987                       DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN,
988                       "Could not determine PID for '%s'", service);
989       goto failed;
990     }
991
992   pid32 = pid;
993   if (! dbus_message_append_args (reply,
994                                   DBUS_TYPE_UINT32, &pid32,
995                                   DBUS_TYPE_INVALID))
996     goto oom;
997
998   if (! bus_transaction_send_from_driver (transaction, connection, reply))
999     goto oom;
1000
1001   dbus_message_unref (reply);
1002
1003   return TRUE;
1004
1005  oom:
1006   BUS_SET_OOM (error);
1007
1008  failed:
1009   _DBUS_ASSERT_ERROR_IS_SET (error);
1010   if (reply)
1011     dbus_message_unref (reply);
1012   return FALSE;
1013 }
1014
1015 static dbus_bool_t
1016 bus_driver_handle_reload_config (DBusConnection *connection,
1017                                  BusTransaction *transaction,
1018                                  DBusMessage    *message,
1019                                  DBusError      *error)
1020 {
1021   BusContext *context;
1022   dbus_bool_t retval;
1023
1024   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1025
1026   retval = FALSE;
1027
1028   context = bus_connection_get_context (connection);
1029   if (!bus_context_reload_config (context, error))
1030     {
1031       _DBUS_ASSERT_ERROR_IS_SET (error);
1032       goto out;
1033     }
1034
1035   retval = TRUE;
1036   
1037  out:
1038   return retval;
1039 }
1040
1041 /* For speed it might be useful to sort this in order of
1042  * frequency of use (but doesn't matter with only a few items
1043  * anyhow)
1044  */
1045 struct
1046 {
1047   const char *name;
1048   const char *in_args;
1049   const char *out_args;
1050   dbus_bool_t (* handler) (DBusConnection *connection,
1051                            BusTransaction *transaction,
1052                            DBusMessage    *message,
1053                            DBusError      *error);
1054 } message_handlers[] = {
1055   { "RequestName",
1056     DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
1057     DBUS_TYPE_UINT32_AS_STRING,
1058     bus_driver_handle_acquire_service },
1059   { "StartServiceByName",
1060     DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
1061     DBUS_TYPE_UINT32_AS_STRING,
1062     bus_driver_handle_activate_service },
1063   { "Hello",
1064     "",
1065     DBUS_TYPE_STRING_AS_STRING,
1066     bus_driver_handle_hello },
1067   { "NameHasOwner",
1068     DBUS_TYPE_STRING_AS_STRING,
1069     DBUS_TYPE_BOOLEAN_AS_STRING,
1070     bus_driver_handle_service_exists },
1071   { "ListNames",
1072     "",
1073     DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
1074     bus_driver_handle_list_services },
1075   { "AddMatch",
1076     DBUS_TYPE_STRING_AS_STRING,
1077     "",
1078     bus_driver_handle_add_match },
1079   { "RemoveMatch",
1080     DBUS_TYPE_STRING_AS_STRING,
1081     "",
1082     bus_driver_handle_remove_match },
1083   { "GetNameOwner",
1084     DBUS_TYPE_STRING_AS_STRING,
1085     DBUS_TYPE_STRING_AS_STRING,
1086     bus_driver_handle_get_service_owner },
1087   { "GetConnectionUnixUser",
1088     DBUS_TYPE_STRING_AS_STRING,
1089     DBUS_TYPE_UINT32_AS_STRING,
1090     bus_driver_handle_get_connection_unix_user },
1091   { "GetConnectionUnixProcessID",
1092     DBUS_TYPE_STRING_AS_STRING,
1093     DBUS_TYPE_UINT32_AS_STRING,
1094     bus_driver_handle_get_connection_unix_process_id },
1095   { "ReloadConfig",
1096     "",
1097     "",
1098     bus_driver_handle_reload_config }
1099 };
1100
1101 static dbus_bool_t
1102 bus_driver_handle_introspect (DBusConnection *connection,
1103                               BusTransaction *transaction,
1104                               DBusMessage    *message,
1105                               DBusError      *error)
1106 {
1107   DBusString xml;
1108   DBusMessage *reply;
1109   const char *v_STRING;
1110   int i;
1111
1112   _dbus_verbose ("Introspect() on bus driver\n");
1113   
1114   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1115
1116   reply = NULL;
1117
1118   if (! dbus_message_get_args (message, error,
1119                                DBUS_TYPE_INVALID))
1120     {
1121       _DBUS_ASSERT_ERROR_IS_SET (error);
1122       return FALSE;
1123     }
1124
1125   if (!_dbus_string_init (&xml))
1126     {
1127       BUS_SET_OOM (error);
1128       return FALSE;
1129     }
1130
1131   if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE))
1132     goto oom;
1133   if (!_dbus_string_append (&xml, "<node>\n"))
1134     goto oom;
1135   if (!_dbus_string_append_printf (&xml, "  <interface name=\"%s\">\n", DBUS_INTERFACE_INTROSPECTABLE))
1136     goto oom;
1137   if (!_dbus_string_append (&xml, "    <method name=\"Introspect\">\n"))
1138     goto oom;
1139   if (!_dbus_string_append_printf (&xml, "      <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING))
1140     goto oom;
1141   if (!_dbus_string_append (&xml, "    </method>\n"))
1142     goto oom;
1143   if (!_dbus_string_append (&xml, "  </interface>\n"))
1144     goto oom;
1145
1146   if (!_dbus_string_append_printf (&xml, "  <interface name=\"%s\">\n",
1147                                    DBUS_INTERFACE_DBUS))
1148     goto oom;
1149
1150   i = 0;
1151   while (i < _DBUS_N_ELEMENTS (message_handlers))
1152     {
1153       if (!_dbus_string_append_printf (&xml, "    <method name=\"%s\">\n",
1154                                        message_handlers[i].name))
1155         goto oom;
1156
1157       /* This hacky mess can probably get mopped up eventually when the
1158        * introspection format is related to the signature format
1159        */
1160       
1161       if (strcmp (message_handlers[i].in_args, "") == 0)
1162         ;
1163       else if (strcmp (message_handlers[i].in_args,
1164                        DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING) == 0)
1165         {
1166           if (!_dbus_string_append_printf (&xml, "      <arg direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING))
1167             goto oom;
1168           if (!_dbus_string_append_printf (&xml, "      <arg direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_UINT32_AS_STRING))
1169             goto oom;
1170         }
1171       else if (strcmp (message_handlers[i].in_args,
1172                        DBUS_TYPE_STRING_AS_STRING) == 0)
1173         {
1174           if (!_dbus_string_append_printf (&xml, "      <arg direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING))
1175             goto oom;
1176         }
1177       else
1178         {
1179           _dbus_warn ("Lack introspection code for in sig '%s'\n",
1180                       message_handlers[i].in_args);
1181           _dbus_assert_not_reached ("FIXME introspection missing");
1182         }
1183
1184       if (strcmp (message_handlers[i].out_args, "") == 0)
1185         ;
1186       else if (strcmp (message_handlers[i].out_args,
1187                        DBUS_TYPE_STRING_AS_STRING) == 0)
1188         {
1189           if (!_dbus_string_append_printf (&xml, "      <arg direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING))
1190             goto oom;
1191         }
1192       else if (strcmp (message_handlers[i].out_args,
1193                        DBUS_TYPE_BOOLEAN_AS_STRING) == 0)
1194         {
1195           if (!_dbus_string_append_printf (&xml, "      <arg direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_BOOLEAN_AS_STRING))
1196             goto oom;
1197         }
1198       else if (strcmp (message_handlers[i].out_args,
1199                        DBUS_TYPE_UINT32_AS_STRING) == 0)
1200         {
1201           if (!_dbus_string_append_printf (&xml, "      <arg direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_UINT32_AS_STRING))
1202             goto oom;
1203         }
1204       else if (strcmp (message_handlers[i].out_args,
1205                        DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING) == 0)
1206         {
1207           /* FIXME introspection format doesn't handle arrays yet */
1208           if (!_dbus_string_append_printf (&xml, "      <arg direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING))
1209             goto oom;
1210         }
1211       else
1212         {
1213           _dbus_warn ("Lack introspection code for out sig '%s'\n",
1214                       message_handlers[i].out_args);
1215           _dbus_assert_not_reached ("FIXME introspection missing");
1216         }
1217       
1218       if (!_dbus_string_append (&xml, "    </method>\n"))
1219         goto oom;
1220       
1221       ++i;
1222     }
1223   
1224   if (!_dbus_string_append (&xml, "  </interface>\n"))
1225     goto oom;
1226   
1227   if (!_dbus_string_append (&xml, "</node>\n"))
1228     goto oom;
1229
1230   reply = dbus_message_new_method_return (message);
1231   if (reply == NULL)
1232     goto oom;
1233
1234   v_STRING = _dbus_string_get_const_data (&xml);
1235   if (! dbus_message_append_args (reply,
1236                                   DBUS_TYPE_STRING, &v_STRING,
1237                                   DBUS_TYPE_INVALID))
1238     goto oom;
1239
1240   if (! bus_transaction_send_from_driver (transaction, connection, reply))
1241     goto oom;
1242
1243   dbus_message_unref (reply);
1244   _dbus_string_free (&xml);
1245
1246   return TRUE;
1247
1248  oom:
1249   BUS_SET_OOM (error);
1250
1251   if (reply)
1252     dbus_message_unref (reply);
1253
1254   _dbus_string_free (&xml);
1255   
1256   return FALSE;
1257 }
1258
1259 dbus_bool_t
1260 bus_driver_handle_message (DBusConnection *connection,
1261                            BusTransaction *transaction,
1262                            DBusMessage    *message,
1263                            DBusError      *error)
1264 {
1265   const char *name, *sender, *interface;
1266   int i;
1267
1268   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1269
1270   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
1271     {
1272       _dbus_verbose ("Driver got a non-method-call message, ignoring\n");
1273       return TRUE; /* we just ignore this */
1274     }
1275
1276   if (dbus_message_is_method_call (message,
1277                                    DBUS_INTERFACE_INTROSPECTABLE,
1278                                    "Introspect"))
1279     return bus_driver_handle_introspect (connection, transaction, message, error);
1280   
1281   interface = dbus_message_get_interface (message);
1282   if (interface == NULL)
1283     interface = DBUS_INTERFACE_DBUS;
1284   
1285   _dbus_assert (dbus_message_get_member (message) != NULL);
1286   
1287   name = dbus_message_get_member (message);
1288   sender = dbus_message_get_sender (message);
1289   
1290   if (strcmp (interface,
1291               DBUS_INTERFACE_DBUS) != 0)
1292     {
1293       _dbus_verbose ("Driver got message to unknown interface \"%s\"\n",
1294                      interface);
1295       goto unknown;
1296     }
1297   
1298   _dbus_verbose ("Driver got a method call: %s\n",
1299                  dbus_message_get_member (message));
1300   
1301   /* security checks should have kept this from getting here */
1302   _dbus_assert (sender != NULL || strcmp (name, "Hello") == 0);
1303   
1304   i = 0;
1305   while (i < _DBUS_N_ELEMENTS (message_handlers))
1306     {
1307       if (strcmp (message_handlers[i].name, name) == 0)
1308         {
1309           _dbus_verbose ("Found driver handler for %s\n", name);
1310
1311           if (!dbus_message_has_signature (message, message_handlers[i].in_args))
1312             {
1313               _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1314               _dbus_verbose ("Call to %s has wrong args (%s, expected %s)\n",
1315                              name, dbus_message_get_signature (message),
1316                              message_handlers[i].in_args);
1317               
1318               dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
1319                               "Call to %s has wrong args (%s, expected %s)\n",
1320                               name, dbus_message_get_signature (message),
1321                               message_handlers[i].in_args);
1322               _DBUS_ASSERT_ERROR_IS_SET (error);
1323               return FALSE;
1324             }
1325           
1326           if ((* message_handlers[i].handler) (connection, transaction, message, error))
1327             {
1328               _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1329               _dbus_verbose ("Driver handler succeeded\n");
1330               return TRUE;
1331             }
1332           else
1333             {
1334               _DBUS_ASSERT_ERROR_IS_SET (error);
1335               _dbus_verbose ("Driver handler returned failure\n");
1336               return FALSE;
1337             }
1338         }
1339       
1340       ++i;
1341     }
1342
1343  unknown:
1344   _dbus_verbose ("No driver handler for message \"%s\"\n",
1345                  name);
1346
1347   dbus_set_error (error, DBUS_ERROR_UNKNOWN_METHOD,
1348                   "%s does not understand message %s",
1349                   DBUS_SERVICE_DBUS, name);
1350   
1351   return FALSE;
1352 }
1353
1354 void
1355 bus_driver_remove_connection (DBusConnection *connection)
1356 {
1357   /* FIXME Does nothing for now, should unregister the connection
1358    * with the bus driver.
1359    */
1360 }