Improve GSettings test coverage
[platform/upstream/glib.git] / gio / gdbusaddress.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <errno.h>
29
30 #include "gioerror.h"
31 #include "gdbusutils.h"
32 #include "gdbusaddress.h"
33 #include "gdbuserror.h"
34 #include "gioenumtypes.h"
35 #include "gnetworkaddress.h"
36 #include "gsocketclient.h"
37 #include "giostream.h"
38 #include "gasyncresult.h"
39 #include "gsimpleasyncresult.h"
40 #include "gdbusprivate.h"
41 #include "giomodule-priv.h"
42 #include "gdbusdaemon.h"
43
44 #ifdef G_OS_UNIX
45 #include <gio/gunixsocketaddress.h>
46 #endif
47
48 #ifdef G_OS_WIN32
49 #include <windows.h>
50 #include <io.h>
51 #include <conio.h>
52 #endif
53
54 #include "glibintl.h"
55
56 /**
57  * SECTION:gdbusaddress
58  * @title: D-Bus Addresses
59  * @short_description: D-Bus connection endpoints
60  * @include: gio/gio.h
61  *
62  * Routines for working with D-Bus addresses. A D-Bus address is a string
63  * like "unix:tmpdir=/tmp/my-app-name". The exact format of addresses
64  * is explained in detail in the <link linkend="http://dbus.freedesktop.org/doc/dbus-specification.html&num;addresses">D-Bus specification</link>.
65  */
66
67 static gchar *get_session_address_platform_specific (GError **error);
68
69 /* ---------------------------------------------------------------------------------------------------- */
70
71 /**
72  * g_dbus_is_address:
73  * @string: A string.
74  *
75  * Checks if @string is a D-Bus address.
76  *
77  * This doesn't check if @string is actually supported by #GDBusServer
78  * or #GDBusConnection - use g_dbus_is_supported_address() to do more
79  * checks.
80  *
81  * Returns: %TRUE if @string is a valid D-Bus address, %FALSE otherwise.
82  *
83  * Since: 2.26
84  */
85 gboolean
86 g_dbus_is_address (const gchar *string)
87 {
88   guint n;
89   gchar **a;
90   gboolean ret;
91
92   ret = FALSE;
93
94   g_return_val_if_fail (string != NULL, FALSE);
95
96   a = g_strsplit (string, ";", 0);
97   if (a[0] == NULL)
98     goto out;
99
100   for (n = 0; a[n] != NULL; n++)
101     {
102       if (!_g_dbus_address_parse_entry (a[n],
103                                         NULL,
104                                         NULL,
105                                         NULL))
106         goto out;
107     }
108
109   ret = TRUE;
110
111  out:
112   g_strfreev (a);
113   return ret;
114 }
115
116 static gboolean
117 is_valid_unix (const gchar  *address_entry,
118                GHashTable   *key_value_pairs,
119                GError      **error)
120 {
121   gboolean ret;
122   GList *keys;
123   GList *l;
124   const gchar *path;
125   const gchar *tmpdir;
126   const gchar *abstract;
127
128   ret = FALSE;
129   keys = NULL;
130   path = NULL;
131   tmpdir = NULL;
132   abstract = NULL;
133
134   keys = g_hash_table_get_keys (key_value_pairs);
135   for (l = keys; l != NULL; l = l->next)
136     {
137       const gchar *key = l->data;
138       if (g_strcmp0 (key, "path") == 0)
139         path = g_hash_table_lookup (key_value_pairs, key);
140       else if (g_strcmp0 (key, "tmpdir") == 0)
141         tmpdir = g_hash_table_lookup (key_value_pairs, key);
142       else if (g_strcmp0 (key, "abstract") == 0)
143         abstract = g_hash_table_lookup (key_value_pairs, key);
144       else
145         {
146           g_set_error (error,
147                        G_IO_ERROR,
148                        G_IO_ERROR_INVALID_ARGUMENT,
149                        _("Unsupported key `%s' in address entry `%s'"),
150                        key,
151                        address_entry);
152           goto out;
153         }
154     }
155
156   if (path != NULL)
157     {
158       if (tmpdir != NULL || abstract != NULL)
159         goto meaningless;
160     }
161   else if (tmpdir != NULL)
162     {
163       if (path != NULL || abstract != NULL)
164         goto meaningless;
165     }
166   else if (abstract != NULL)
167     {
168       if (path != NULL || tmpdir != NULL)
169         goto meaningless;
170     }
171   else
172     {
173       g_set_error (error,
174                    G_IO_ERROR,
175                    G_IO_ERROR_INVALID_ARGUMENT,
176                    _("Address `%s' is invalid (need exactly one of path, tmpdir or abstract keys)"),
177                    address_entry);
178       goto out;
179     }
180
181
182   ret= TRUE;
183   goto out;
184
185  meaningless:
186   g_set_error (error,
187                G_IO_ERROR,
188                G_IO_ERROR_INVALID_ARGUMENT,
189                _("Meaningless key/value pair combination in address entry `%s'"),
190                address_entry);
191
192  out:
193   g_list_free (keys);
194
195   return ret;
196 }
197
198 static gboolean
199 is_valid_nonce_tcp (const gchar  *address_entry,
200                     GHashTable   *key_value_pairs,
201                     GError      **error)
202 {
203   gboolean ret;
204   GList *keys;
205   GList *l;
206   const gchar *host;
207   const gchar *port;
208   const gchar *family;
209   const gchar *nonce_file;
210   gint port_num;
211   gchar *endp;
212
213   ret = FALSE;
214   keys = NULL;
215   host = NULL;
216   port = NULL;
217   family = NULL;
218   nonce_file = NULL;
219
220   keys = g_hash_table_get_keys (key_value_pairs);
221   for (l = keys; l != NULL; l = l->next)
222     {
223       const gchar *key = l->data;
224       if (g_strcmp0 (key, "host") == 0)
225         host = g_hash_table_lookup (key_value_pairs, key);
226       else if (g_strcmp0 (key, "port") == 0)
227         port = g_hash_table_lookup (key_value_pairs, key);
228       else if (g_strcmp0 (key, "family") == 0)
229         family = g_hash_table_lookup (key_value_pairs, key);
230       else if (g_strcmp0 (key, "noncefile") == 0)
231         nonce_file = g_hash_table_lookup (key_value_pairs, key);
232       else
233         {
234           g_set_error (error,
235                        G_IO_ERROR,
236                        G_IO_ERROR_INVALID_ARGUMENT,
237                        _("Unsupported key `%s' in address entry `%s'"),
238                        key,
239                        address_entry);
240           goto out;
241         }
242     }
243
244   if (port != NULL)
245     {
246       port_num = strtol (port, &endp, 10);
247       if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
248         {
249           g_set_error (error,
250                        G_IO_ERROR,
251                        G_IO_ERROR_INVALID_ARGUMENT,
252                        _("Error in address `%s' - the port attribute is malformed"),
253                        address_entry);
254           goto out;
255         }
256     }
257
258   if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
259     {
260       g_set_error (error,
261                    G_IO_ERROR,
262                    G_IO_ERROR_INVALID_ARGUMENT,
263                    _("Error in address `%s' - the family attribute is malformed"),
264                    address_entry);
265       goto out;
266     }
267
268   if (host != NULL)
269     {
270       /* TODO: validate host */
271     }
272
273   nonce_file = nonce_file; /* To avoid -Wunused-but-set-variable */
274
275   ret= TRUE;
276
277  out:
278   g_list_free (keys);
279
280   return ret;
281 }
282
283 static gboolean
284 is_valid_tcp (const gchar  *address_entry,
285               GHashTable   *key_value_pairs,
286               GError      **error)
287 {
288   gboolean ret;
289   GList *keys;
290   GList *l;
291   const gchar *host;
292   const gchar *port;
293   const gchar *family;
294   gint port_num;
295   gchar *endp;
296
297   ret = FALSE;
298   keys = NULL;
299   host = NULL;
300   port = NULL;
301   family = NULL;
302
303   keys = g_hash_table_get_keys (key_value_pairs);
304   for (l = keys; l != NULL; l = l->next)
305     {
306       const gchar *key = l->data;
307       if (g_strcmp0 (key, "host") == 0)
308         host = g_hash_table_lookup (key_value_pairs, key);
309       else if (g_strcmp0 (key, "port") == 0)
310         port = g_hash_table_lookup (key_value_pairs, key);
311       else if (g_strcmp0 (key, "family") == 0)
312         family = g_hash_table_lookup (key_value_pairs, key);
313       else
314         {
315           g_set_error (error,
316                        G_IO_ERROR,
317                        G_IO_ERROR_INVALID_ARGUMENT,
318                        _("Unsupported key `%s' in address entry `%s'"),
319                        key,
320                        address_entry);
321           goto out;
322         }
323     }
324
325   if (port != NULL)
326     {
327       port_num = strtol (port, &endp, 10);
328       if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
329         {
330           g_set_error (error,
331                        G_IO_ERROR,
332                        G_IO_ERROR_INVALID_ARGUMENT,
333                        _("Error in address `%s' - the port attribute is malformed"),
334                        address_entry);
335           goto out;
336         }
337     }
338
339   if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
340     {
341       g_set_error (error,
342                    G_IO_ERROR,
343                    G_IO_ERROR_INVALID_ARGUMENT,
344                    _("Error in address `%s' - the family attribute is malformed"),
345                    address_entry);
346       goto out;
347     }
348
349   if (host != NULL)
350     {
351       /* TODO: validate host */
352     }
353
354   ret= TRUE;
355
356  out:
357   g_list_free (keys);
358
359   return ret;
360 }
361
362 /**
363  * g_dbus_is_supported_address:
364  * @string: A string.
365  * @error: Return location for error or %NULL.
366  *
367  * Like g_dbus_is_address() but also checks if the library suppors the
368  * transports in @string and that key/value pairs for each transport
369  * are valid.
370  *
371  * Returns: %TRUE if @string is a valid D-Bus address that is
372  * supported by this library, %FALSE if @error is set.
373  *
374  * Since: 2.26
375  */
376 gboolean
377 g_dbus_is_supported_address (const gchar  *string,
378                              GError      **error)
379 {
380   guint n;
381   gchar **a;
382   gboolean ret;
383
384   ret = FALSE;
385
386   g_return_val_if_fail (string != NULL, FALSE);
387   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
388
389   a = g_strsplit (string, ";", 0);
390   for (n = 0; a[n] != NULL; n++)
391     {
392       gchar *transport_name;
393       GHashTable *key_value_pairs;
394       gboolean supported;
395
396       if (!_g_dbus_address_parse_entry (a[n],
397                                         &transport_name,
398                                         &key_value_pairs,
399                                         error))
400         goto out;
401
402       supported = FALSE;
403       if (g_strcmp0 (transport_name, "unix") == 0)
404         supported = is_valid_unix (a[n], key_value_pairs, error);
405       else if (g_strcmp0 (transport_name, "tcp") == 0)
406         supported = is_valid_tcp (a[n], key_value_pairs, error);
407       else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
408         supported = is_valid_nonce_tcp (a[n], key_value_pairs, error);
409       else if (g_strcmp0 (a[n], "autolaunch:") == 0)
410         supported = TRUE;
411
412       g_free (transport_name);
413       g_hash_table_unref (key_value_pairs);
414
415       if (!supported)
416         goto out;
417     }
418
419   ret = TRUE;
420
421  out:
422   g_strfreev (a);
423
424   g_assert (ret || (!ret && (error == NULL || *error != NULL)));
425
426   return ret;
427 }
428
429 gboolean
430 _g_dbus_address_parse_entry (const gchar  *address_entry,
431                              gchar       **out_transport_name,
432                              GHashTable  **out_key_value_pairs,
433                              GError      **error)
434 {
435   gboolean ret;
436   GHashTable *key_value_pairs;
437   gchar *transport_name;
438   gchar **kv_pairs;
439   const gchar *s;
440   guint n;
441
442   ret = FALSE;
443   kv_pairs = NULL;
444   transport_name = NULL;
445   key_value_pairs = NULL;
446
447   s = strchr (address_entry, ':');
448   if (s == NULL)
449     {
450       g_set_error (error,
451                    G_IO_ERROR,
452                    G_IO_ERROR_INVALID_ARGUMENT,
453                    _("Address element `%s' does not contain a colon (:)"),
454                    address_entry);
455       goto out;
456     }
457
458   transport_name = g_strndup (address_entry, s - address_entry);
459   key_value_pairs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
460
461   kv_pairs = g_strsplit (s + 1, ",", 0);
462   for (n = 0; kv_pairs != NULL && kv_pairs[n] != NULL; n++)
463     {
464       const gchar *kv_pair = kv_pairs[n];
465       gchar *key;
466       gchar *value;
467
468       s = strchr (kv_pair, '=');
469       if (s == NULL)
470         {
471           g_set_error (error,
472                        G_IO_ERROR,
473                        G_IO_ERROR_INVALID_ARGUMENT,
474                        _("Key/Value pair %d, `%s', in address element `%s' does not contain an equal sign"),
475                        n,
476                        kv_pair,
477                        address_entry);
478           goto out;
479         }
480
481       key = g_uri_unescape_segment (kv_pair, s, NULL);
482       value = g_uri_unescape_segment (s + 1, kv_pair + strlen (kv_pair), NULL);
483       if (key == NULL || value == NULL)
484         {
485           g_set_error (error,
486                        G_IO_ERROR,
487                        G_IO_ERROR_INVALID_ARGUMENT,
488                        _("Error unescaping key or value in Key/Value pair %d, `%s', in address element `%s'"),
489                        n,
490                        kv_pair,
491                        address_entry);
492           g_free (key);
493           g_free (value);
494           goto out;
495         }
496       g_hash_table_insert (key_value_pairs, key, value);
497     }
498
499   ret = TRUE;
500
501 out:
502   g_strfreev (kv_pairs);
503   if (ret)
504     {
505       if (out_transport_name != NULL)
506         *out_transport_name = transport_name;
507       else
508         g_free (transport_name);
509       if (out_key_value_pairs != NULL)
510         *out_key_value_pairs = key_value_pairs;
511       else if (key_value_pairs != NULL)
512         g_hash_table_unref (key_value_pairs);
513     }
514   else
515     {
516       g_free (transport_name);
517       if (key_value_pairs != NULL)
518         g_hash_table_unref (key_value_pairs);
519     }
520   return ret;
521 }
522
523 /* ---------------------------------------------------------------------------------------------------- */
524
525 static GIOStream *
526 g_dbus_address_try_connect_one (const gchar   *address_entry,
527                                 gchar        **out_guid,
528                                 GCancellable  *cancellable,
529                                 GError       **error);
530
531 /* TODO: Declare an extension point called GDBusTransport (or similar)
532  * and move code below to extensions implementing said extension
533  * point. That way we can implement a D-Bus transport over X11 without
534  * making libgio link to libX11...
535  */
536 static GIOStream *
537 g_dbus_address_connect (const gchar   *address_entry,
538                         const gchar   *transport_name,
539                         GHashTable    *key_value_pairs,
540                         GCancellable  *cancellable,
541                         GError       **error)
542 {
543   GIOStream *ret;
544   GSocketConnectable *connectable;
545   const gchar *nonce_file;
546
547   connectable = NULL;
548   ret = NULL;
549   nonce_file = NULL;
550
551   if (FALSE)
552     {
553     }
554 #ifdef G_OS_UNIX
555   else if (g_strcmp0 (transport_name, "unix") == 0)
556     {
557       const gchar *path;
558       const gchar *abstract;
559       path = g_hash_table_lookup (key_value_pairs, "path");
560       abstract = g_hash_table_lookup (key_value_pairs, "abstract");
561       if ((path == NULL && abstract == NULL) || (path != NULL && abstract != NULL))
562         {
563           g_set_error (error,
564                        G_IO_ERROR,
565                        G_IO_ERROR_INVALID_ARGUMENT,
566                        _("Error in address `%s' - the unix transport requires exactly one of the "
567                          "keys `path' or `abstract' to be set"),
568                        address_entry);
569         }
570       else if (path != NULL)
571         {
572           connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path));
573         }
574       else if (abstract != NULL)
575         {
576           connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract,
577                                                                                    -1,
578                                                                                    G_UNIX_SOCKET_ADDRESS_ABSTRACT));
579         }
580       else
581         {
582           g_assert_not_reached ();
583         }
584     }
585 #endif
586   else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0)
587     {
588       const gchar *s;
589       const gchar *host;
590       glong port;
591       gchar *endp;
592       gboolean is_nonce;
593
594       is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0);
595
596       host = g_hash_table_lookup (key_value_pairs, "host");
597       if (host == NULL)
598         {
599           g_set_error (error,
600                        G_IO_ERROR,
601                        G_IO_ERROR_INVALID_ARGUMENT,
602                        _("Error in address `%s' - the host attribute is missing or malformed"),
603                        address_entry);
604           goto out;
605         }
606
607       s = g_hash_table_lookup (key_value_pairs, "port");
608       if (s == NULL)
609         s = "0";
610       port = strtol (s, &endp, 10);
611       if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536)
612         {
613           g_set_error (error,
614                        G_IO_ERROR,
615                        G_IO_ERROR_INVALID_ARGUMENT,
616                        _("Error in address `%s' - the port attribute is missing or malformed"),
617                        address_entry);
618           goto out;
619         }
620
621
622       if (is_nonce)
623         {
624           nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
625           if (nonce_file == NULL)
626             {
627               g_set_error (error,
628                            G_IO_ERROR,
629                            G_IO_ERROR_INVALID_ARGUMENT,
630                            _("Error in address `%s' - the noncefile attribute is missing or malformed"),
631                            address_entry);
632               goto out;
633             }
634         }
635
636       /* TODO: deal with family key/value-pair */
637       connectable = g_network_address_new (host, port);
638     }
639   else if (g_strcmp0 (address_entry, "autolaunch:") == 0)
640     {
641       gchar *autolaunch_address;
642       autolaunch_address = get_session_address_platform_specific (error);
643       if (autolaunch_address != NULL)
644         {
645           ret = g_dbus_address_try_connect_one (autolaunch_address, NULL, cancellable, error);
646           g_free (autolaunch_address);
647           goto out;
648         }
649       else
650         {
651           g_prefix_error (error, _("Error auto-launching: "));
652         }
653     }
654   else
655     {
656       g_set_error (error,
657                    G_IO_ERROR,
658                    G_IO_ERROR_INVALID_ARGUMENT,
659                    _("Unknown or unsupported transport `%s' for address `%s'"),
660                    transport_name,
661                    address_entry);
662     }
663
664   if (connectable != NULL)
665     {
666       GSocketClient *client;
667       GSocketConnection *connection;
668
669       g_assert (ret == NULL);
670       client = g_socket_client_new ();
671       connection = g_socket_client_connect (client,
672                                             connectable,
673                                             cancellable,
674                                             error);
675       g_object_unref (connectable);
676       g_object_unref (client);
677       if (connection == NULL)
678         goto out;
679
680       ret = G_IO_STREAM (connection);
681
682       if (nonce_file != NULL)
683         {
684           gchar nonce_contents[16 + 1];
685           size_t num_bytes_read;
686           FILE *f;
687
688           /* be careful to read only 16 bytes - we also check that the file is only 16 bytes long */
689           f = fopen (nonce_file, "rb");
690           if (f == NULL)
691             {
692               g_set_error (error,
693                            G_IO_ERROR,
694                            G_IO_ERROR_INVALID_ARGUMENT,
695                            _("Error opening nonce file `%s': %s"),
696                            nonce_file,
697                            g_strerror (errno));
698               g_object_unref (ret);
699               ret = NULL;
700               goto out;
701             }
702           num_bytes_read = fread (nonce_contents,
703                                   sizeof (gchar),
704                                   16 + 1,
705                                   f);
706           if (num_bytes_read != 16)
707             {
708               if (num_bytes_read == 0)
709                 {
710                   g_set_error (error,
711                                G_IO_ERROR,
712                                G_IO_ERROR_INVALID_ARGUMENT,
713                                _("Error reading from nonce file `%s': %s"),
714                                nonce_file,
715                                g_strerror (errno));
716                 }
717               else
718                 {
719                   g_set_error (error,
720                                G_IO_ERROR,
721                                G_IO_ERROR_INVALID_ARGUMENT,
722                                _("Error reading from nonce file `%s', expected 16 bytes, got %d"),
723                                nonce_file,
724                                (gint) num_bytes_read);
725                 }
726               g_object_unref (ret);
727               ret = NULL;
728               fclose (f);
729               goto out;
730             }
731           fclose (f);
732
733           if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret),
734                                           nonce_contents,
735                                           16,
736                                           NULL,
737                                           cancellable,
738                                           error))
739             {
740               g_prefix_error (error, _("Error writing contents of nonce file `%s' to stream:"), nonce_file);
741               g_object_unref (ret);
742               ret = NULL;
743               goto out;
744             }
745         }
746     }
747
748  out:
749
750   return ret;
751 }
752
753 static GIOStream *
754 g_dbus_address_try_connect_one (const gchar   *address_entry,
755                                 gchar        **out_guid,
756                                 GCancellable  *cancellable,
757                                 GError       **error)
758 {
759   GIOStream *ret;
760   GHashTable *key_value_pairs;
761   gchar *transport_name;
762   const gchar *guid;
763
764   ret = NULL;
765   transport_name = NULL;
766   key_value_pairs = NULL;
767
768   if (!_g_dbus_address_parse_entry (address_entry,
769                                     &transport_name,
770                                     &key_value_pairs,
771                                     error))
772     goto out;
773
774   ret = g_dbus_address_connect (address_entry,
775                                 transport_name,
776                                 key_value_pairs,
777                                 cancellable,
778                                 error);
779   if (ret == NULL)
780     goto out;
781
782   guid = g_hash_table_lookup (key_value_pairs, "guid");
783   if (guid != NULL && out_guid != NULL)
784     *out_guid = g_strdup (guid);
785
786 out:
787   g_free (transport_name);
788   if (key_value_pairs != NULL)
789     g_hash_table_unref (key_value_pairs);
790   return ret;
791 }
792
793
794 /* ---------------------------------------------------------------------------------------------------- */
795
796 typedef struct {
797   gchar *address;
798   GIOStream *stream;
799   gchar *guid;
800 } GetStreamData;
801
802 static void
803 get_stream_data_free (GetStreamData *data)
804 {
805   g_free (data->address);
806   if (data->stream != NULL)
807     g_object_unref (data->stream);
808   g_free (data->guid);
809   g_free (data);
810 }
811
812 static void
813 get_stream_thread_func (GSimpleAsyncResult *res,
814                         GObject            *object,
815                         GCancellable       *cancellable)
816 {
817   GetStreamData *data;
818   GError *error;
819
820   data = g_simple_async_result_get_op_res_gpointer (res);
821
822   error = NULL;
823   data->stream = g_dbus_address_get_stream_sync (data->address,
824                                                  &data->guid,
825                                                  cancellable,
826                                                  &error);
827   if (data->stream == NULL)
828     g_simple_async_result_take_error (res, error);
829 }
830
831 /**
832  * g_dbus_address_get_stream:
833  * @address: A valid D-Bus address.
834  * @cancellable: (allow-none): A #GCancellable or %NULL.
835  * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
836  * @user_data: Data to pass to @callback.
837  *
838  * Asynchronously connects to an endpoint specified by @address and
839  * sets up the connection so it is in a state to run the client-side
840  * of the D-Bus authentication conversation.
841  *
842  * When the operation is finished, @callback will be invoked. You can
843  * then call g_dbus_address_get_stream_finish() to get the result of
844  * the operation.
845  *
846  * This is an asynchronous failable function. See
847  * g_dbus_address_get_stream_sync() for the synchronous version.
848  *
849  * Since: 2.26
850  */
851 void
852 g_dbus_address_get_stream (const gchar         *address,
853                            GCancellable        *cancellable,
854                            GAsyncReadyCallback  callback,
855                            gpointer             user_data)
856 {
857   GSimpleAsyncResult *res;
858   GetStreamData *data;
859
860   g_return_if_fail (address != NULL);
861
862   res = g_simple_async_result_new (NULL,
863                                    callback,
864                                    user_data,
865                                    g_dbus_address_get_stream);
866   g_simple_async_result_set_check_cancellable (res, cancellable);
867   data = g_new0 (GetStreamData, 1);
868   data->address = g_strdup (address);
869   g_simple_async_result_set_op_res_gpointer (res,
870                                              data,
871                                              (GDestroyNotify) get_stream_data_free);
872   g_simple_async_result_run_in_thread (res,
873                                        get_stream_thread_func,
874                                        G_PRIORITY_DEFAULT,
875                                        cancellable);
876   g_object_unref (res);
877 }
878
879 /**
880  * g_dbus_address_get_stream_finish:
881  * @res: A #GAsyncResult obtained from the GAsyncReadyCallback passed to g_dbus_address_get_stream().
882  * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
883  * @error: Return location for error or %NULL.
884  *
885  * Finishes an operation started with g_dbus_address_get_stream().
886  *
887  * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
888  *
889  * Since: 2.26
890  */
891 GIOStream *
892 g_dbus_address_get_stream_finish (GAsyncResult        *res,
893                                   gchar              **out_guid,
894                                   GError             **error)
895 {
896   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
897   GetStreamData *data;
898   GIOStream *ret;
899
900   g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
901   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
902
903   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_address_get_stream);
904
905   ret = NULL;
906
907   data = g_simple_async_result_get_op_res_gpointer (simple);
908   if (g_simple_async_result_propagate_error (simple, error))
909     goto out;
910
911   ret = g_object_ref (data->stream);
912   if (out_guid != NULL)
913     *out_guid = g_strdup (data->guid);
914
915  out:
916   return ret;
917 }
918
919 /**
920  * g_dbus_address_get_stream_sync:
921  * @address: A valid D-Bus address.
922  * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
923  * @cancellable: (allow-none): A #GCancellable or %NULL.
924  * @error: Return location for error or %NULL.
925  *
926  * Synchronously connects to an endpoint specified by @address and
927  * sets up the connection so it is in a state to run the client-side
928  * of the D-Bus authentication conversation.
929  *
930  * This is a synchronous failable function. See
931  * g_dbus_address_get_stream() for the asynchronous version.
932  *
933  * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
934  *
935  * Since: 2.26
936  */
937 GIOStream *
938 g_dbus_address_get_stream_sync (const gchar   *address,
939                                 gchar        **out_guid,
940                                 GCancellable  *cancellable,
941                                 GError       **error)
942 {
943   GIOStream *ret;
944   gchar **addr_array;
945   guint n;
946   GError *last_error;
947
948   g_return_val_if_fail (address != NULL, NULL);
949   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
950
951   ret = NULL;
952   last_error = NULL;
953
954   addr_array = g_strsplit (address, ";", 0);
955   if (addr_array != NULL && addr_array[0] == NULL)
956     {
957       last_error = g_error_new_literal (G_IO_ERROR,
958                                         G_IO_ERROR_INVALID_ARGUMENT,
959                                         _("The given address is empty"));
960       goto out;
961     }
962
963   for (n = 0; addr_array != NULL && addr_array[n] != NULL; n++)
964     {
965       const gchar *addr = addr_array[n];
966       GError *this_error;
967
968       this_error = NULL;
969       ret = g_dbus_address_try_connect_one (addr,
970                                             out_guid,
971                                             cancellable,
972                                             &this_error);
973       if (ret != NULL)
974         {
975           goto out;
976         }
977       else
978         {
979           g_assert (this_error != NULL);
980           if (last_error != NULL)
981             g_error_free (last_error);
982           last_error = this_error;
983         }
984     }
985
986  out:
987   if (ret != NULL)
988     {
989       if (last_error != NULL)
990         g_error_free (last_error);
991     }
992   else
993     {
994       g_assert (last_error != NULL);
995       g_propagate_error (error, last_error);
996     }
997
998   g_strfreev (addr_array);
999   return ret;
1000 }
1001
1002 /* ---------------------------------------------------------------------------------------------------- */
1003
1004 #ifdef G_OS_UNIX
1005 static gchar *
1006 get_session_address_dbus_launch (GError **error)
1007 {
1008   gchar *ret;
1009   gchar *machine_id;
1010   gchar *command_line;
1011   gchar *launch_stdout;
1012   gchar *launch_stderr;
1013   gint exit_status;
1014   gchar *old_dbus_verbose;
1015   gboolean restore_dbus_verbose;
1016
1017   ret = NULL;
1018   machine_id = NULL;
1019   command_line = NULL;
1020   launch_stdout = NULL;
1021   launch_stderr = NULL;
1022   restore_dbus_verbose = FALSE;
1023   old_dbus_verbose = NULL;
1024
1025   machine_id = _g_dbus_get_machine_id (error);
1026   if (machine_id == NULL)
1027     {
1028       g_prefix_error (error, _("Cannot spawn a message bus without a machine-id: "));
1029       goto out;
1030     }
1031
1032   /* We're using private libdbus facilities here. When everything
1033    * (X11, Mac OS X, Windows) is spec'ed out correctly (not even the
1034    * X11 property is correctly documented right now) we should
1035    * consider using the spec instead of dbus-launch.
1036    *
1037    *   --autolaunch=MACHINEID
1038    *          This option implies that dbus-launch should scan  for  a  previ‐
1039    *          ously-started  session  and  reuse the values found there. If no
1040    *          session is found, it will start a new session. The  --exit-with-
1041    *          session option is implied if --autolaunch is given.  This option
1042    *          is for the exclusive use of libdbus, you do not want to  use  it
1043    *          manually. It may change in the future.
1044    */
1045
1046   /* TODO: maybe provide a variable for where to look for the dbus-launch binary? */
1047   command_line = g_strdup_printf ("dbus-launch --autolaunch=%s --binary-syntax --close-stderr", machine_id);
1048
1049   if (G_UNLIKELY (_g_dbus_debug_address ()))
1050     {
1051       _g_dbus_debug_print_lock ();
1052       g_print ("GDBus-debug:Address: Running `%s' to get bus address (possibly autolaunching)\n", command_line);
1053       old_dbus_verbose = g_strdup (g_getenv ("DBUS_VERBOSE"));
1054       restore_dbus_verbose = TRUE;
1055       g_setenv ("DBUS_VERBOSE", "1", TRUE);
1056       _g_dbus_debug_print_unlock ();
1057     }
1058
1059   if (!g_spawn_command_line_sync (command_line,
1060                                   &launch_stdout,
1061                                   &launch_stderr,
1062                                   &exit_status,
1063                                   error))
1064     {
1065       goto out;
1066     }
1067
1068   if (!g_spawn_check_exit_status (exit_status, error))
1069     {
1070       g_prefix_error (error, _("Error spawning command line `%s': "), command_line);
1071       goto out;
1072     }
1073
1074   /* From the dbus-launch(1) man page:
1075    *
1076    *   --binary-syntax Write to stdout a nul-terminated bus address,
1077    *   then the bus PID as a binary integer of size sizeof(pid_t),
1078    *   then the bus X window ID as a binary integer of size
1079    *   sizeof(long).  Integers are in the machine's byte order, not
1080    *   network byte order or any other canonical byte order.
1081    */
1082   ret = g_strdup (launch_stdout);
1083
1084  out:
1085   if (G_UNLIKELY (_g_dbus_debug_address ()))
1086     {
1087       gchar *s;
1088       _g_dbus_debug_print_lock ();
1089       g_print ("GDBus-debug:Address: dbus-launch output:");
1090       if (launch_stdout != NULL)
1091         {
1092           s = _g_dbus_hexdump (launch_stdout, strlen (launch_stdout) + 1 + sizeof (pid_t) + sizeof (long), 2);
1093           g_print ("\n%s", s);
1094           g_free (s);
1095         }
1096       else
1097         {
1098           g_print (" (none)\n");
1099         }
1100       g_print ("GDBus-debug:Address: dbus-launch stderr output:");
1101       if (launch_stderr != NULL)
1102         g_print ("\n%s", launch_stderr);
1103       else
1104         g_print (" (none)\n");
1105       _g_dbus_debug_print_unlock ();
1106     }
1107
1108   g_free (machine_id);
1109   g_free (command_line);
1110   g_free (launch_stdout);
1111   g_free (launch_stderr);
1112   if (G_UNLIKELY (restore_dbus_verbose))
1113     {
1114       if (old_dbus_verbose != NULL)
1115         g_setenv ("DBUS_VERBOSE", old_dbus_verbose, TRUE);
1116       else
1117         g_unsetenv ("DBUS_VERBOSE");
1118     }
1119   g_free (old_dbus_verbose);
1120   return ret;
1121 }
1122 #endif
1123
1124 #ifdef G_OS_WIN32
1125
1126 #define DBUS_DAEMON_ADDRESS_INFO "DBusDaemonAddressInfo"
1127 #define DBUS_DAEMON_MUTEX "DBusDaemonMutex"
1128 #define UNIQUE_DBUS_INIT_MUTEX "UniqueDBusInitMutex"
1129 #define DBUS_AUTOLAUNCH_MUTEX "DBusAutolaunchMutex"
1130
1131 static void
1132 release_mutex (HANDLE mutex)
1133 {
1134   ReleaseMutex (mutex);
1135   CloseHandle (mutex);
1136 }
1137
1138 static HANDLE
1139 acquire_mutex (const char *mutexname)
1140 {
1141   HANDLE mutex;
1142   DWORD res;
1143
1144   mutex = CreateMutexA (NULL, FALSE, mutexname);
1145   if (!mutex)
1146     return 0;
1147
1148   res = WaitForSingleObject (mutex, INFINITE);
1149   switch (res)
1150     {
1151     case WAIT_ABANDONED:
1152       release_mutex (mutex);
1153       return 0;
1154     case WAIT_FAILED:
1155     case WAIT_TIMEOUT:
1156       return 0;
1157     }
1158
1159   return mutex;
1160 }
1161
1162 static gboolean
1163 is_mutex_owned (const char *mutexname)
1164 {
1165   HANDLE mutex;
1166   gboolean res = FALSE;
1167
1168   mutex = CreateMutexA (NULL, FALSE, mutexname);
1169   if (WaitForSingleObject (mutex, 10) == WAIT_TIMEOUT)
1170     res = TRUE;
1171   else
1172     ReleaseMutex (mutex);
1173   CloseHandle (mutex);
1174
1175   return res;
1176 }
1177
1178 static char *
1179 read_shm (const char *shm_name)
1180 {
1181   HANDLE shared_mem;
1182   char *shared_data;
1183   char *res;
1184   int i;
1185
1186   res = NULL;
1187
1188   for (i = 0; i < 20; i++)
1189     {
1190       shared_mem = OpenFileMappingA (FILE_MAP_READ, FALSE, shm_name);
1191       if (shared_mem != 0)
1192         break;
1193       Sleep (100);
1194     }
1195
1196   if (shared_mem != 0)
1197     {
1198       shared_data = MapViewOfFile (shared_mem, FILE_MAP_READ, 0, 0, 0);
1199       if (shared_data != NULL)
1200         {
1201           res = g_strdup (shared_data);
1202           UnmapViewOfFile (shared_data);
1203         }
1204       CloseHandle (shared_mem);
1205     }
1206
1207   return res;
1208 }
1209
1210 static HANDLE
1211 set_shm (const char *shm_name, const char *value)
1212 {
1213   HANDLE shared_mem;
1214   char *shared_data;
1215
1216   shared_mem = CreateFileMappingA (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
1217                                    0, strlen (value) + 1, shm_name);
1218   if (shared_mem == 0)
1219     return 0;
1220
1221   shared_data = MapViewOfFile (shared_mem, FILE_MAP_WRITE, 0, 0, 0 );
1222   if (shared_data == NULL)
1223     return 0;
1224
1225   strcpy (shared_data, value);
1226
1227   UnmapViewOfFile (shared_data);
1228
1229   return shared_mem;
1230 }
1231
1232 /* These keep state between publish_session_bus and unpublish_session_bus */
1233 static HANDLE published_daemon_mutex;
1234 static HANDLE published_shared_mem;
1235
1236 static gboolean
1237 publish_session_bus (const char *address)
1238 {
1239   HANDLE init_mutex;
1240
1241   init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1242
1243   published_daemon_mutex = CreateMutexA (NULL, FALSE, DBUS_DAEMON_MUTEX);
1244   if (WaitForSingleObject (published_daemon_mutex, 10 ) != WAIT_OBJECT_0)
1245     {
1246       release_mutex (init_mutex);
1247       CloseHandle (published_daemon_mutex);
1248       published_daemon_mutex = NULL;
1249       return FALSE;
1250     }
1251
1252   published_shared_mem = set_shm (DBUS_DAEMON_ADDRESS_INFO, address);
1253   if (!published_shared_mem)
1254     {
1255       release_mutex (init_mutex);
1256       CloseHandle (published_daemon_mutex);
1257       published_daemon_mutex = NULL;
1258       return FALSE;
1259     }
1260
1261   release_mutex (init_mutex);
1262   return TRUE;
1263 }
1264
1265 static void
1266 unpublish_session_bus ()
1267 {
1268   HANDLE init_mutex;
1269
1270   init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1271
1272   CloseHandle (published_shared_mem);
1273   published_shared_mem = NULL;
1274
1275   release_mutex (published_daemon_mutex);
1276   published_daemon_mutex = NULL;
1277
1278   release_mutex (init_mutex);
1279 }
1280
1281 static void
1282 wait_console_window (void)
1283 {
1284   FILE *console = fopen ("CONOUT$", "w");
1285
1286   SetConsoleTitleW (L"gdbus-daemon output. Type any character to close this window.");
1287   fprintf (console, _("(Type any character to close this window)\n"));
1288   fflush (console);
1289   _getch ();
1290 }
1291
1292 static void
1293 open_console_window (void)
1294 {
1295   if (((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE ||
1296        (HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) && AllocConsole ())
1297     {
1298       if ((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE)
1299         freopen ("CONOUT$", "w", stdout);
1300
1301       if ((HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE)
1302         freopen ("CONOUT$", "w", stderr);
1303
1304       SetConsoleTitleW (L"gdbus-daemon debug output.");
1305
1306       atexit (wait_console_window);
1307     }
1308 }
1309 static void
1310 idle_timeout_cb (GDBusDaemon *daemon, gpointer user_data)
1311 {
1312   GMainLoop *loop = user_data;
1313   g_main_loop_quit (loop);
1314 }
1315
1316 __declspec(dllexport) void CALLBACK
1317 g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow)
1318 {
1319   GDBusDaemon *daemon;
1320   GMainLoop *loop;
1321   const char *address;
1322   GError *error = NULL;
1323
1324   if (g_getenv ("GDBUS_DAEMON_DEBUG") != NULL)
1325     open_console_window ();
1326
1327   g_type_init ();
1328
1329   loop = g_main_loop_new (NULL, FALSE);
1330
1331   address = "nonce-tcp:";
1332   daemon = _g_dbus_daemon_new (address, NULL, &error);
1333   if (daemon == NULL)
1334     {
1335       g_printerr ("Can't init bus: %s\n", error->message);
1336       return;
1337     }
1338
1339   g_signal_connect (daemon, "idle-timeout", G_CALLBACK (idle_timeout_cb), loop);
1340
1341   if ( publish_session_bus (_g_dbus_daemon_get_address (daemon)))
1342     {
1343       g_main_loop_run (loop);
1344
1345       unpublish_session_bus ();
1346     }
1347
1348   g_main_loop_unref (loop);
1349   g_object_unref (daemon);
1350 }
1351
1352 static gchar *
1353 get_session_address_dbus_launch (GError **error)
1354 {
1355   HANDLE autolaunch_mutex, init_mutex;
1356   char *address = NULL;
1357   wchar_t gio_path[MAX_PATH+1+200];
1358
1359   autolaunch_mutex = acquire_mutex (DBUS_AUTOLAUNCH_MUTEX);
1360
1361   init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1362
1363   if (is_mutex_owned (DBUS_DAEMON_MUTEX))
1364     address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1365
1366   release_mutex (init_mutex);
1367
1368   if (address == NULL)
1369     {
1370       gio_path[MAX_PATH] = 0;
1371       if (GetModuleFileNameW (_g_io_win32_get_module (), gio_path, MAX_PATH))
1372         {
1373           PROCESS_INFORMATION pi = { 0 };
1374           STARTUPINFOW si = { 0 };
1375           BOOL res;
1376           wchar_t gio_path_short[MAX_PATH];
1377           wchar_t rundll_path[MAX_PATH*2];
1378           wchar_t args[MAX_PATH*4];
1379
1380           GetShortPathNameW (gio_path, gio_path_short, MAX_PATH);
1381
1382           GetWindowsDirectoryW (rundll_path, MAX_PATH);
1383           wcscat (rundll_path, L"\\rundll32.exe");
1384           if (GetFileAttributesW (rundll_path) == INVALID_FILE_ATTRIBUTES)
1385             {
1386               GetSystemDirectoryW (rundll_path, MAX_PATH);
1387               wcscat (rundll_path, L"\\rundll32.exe");
1388             }
1389
1390           wcscpy (args, L"\"");
1391           wcscat (args, rundll_path);
1392           wcscat (args, L"\" ");
1393           wcscat (args, gio_path_short);
1394           wcscat (args, L",g_win32_run_session_bus@16");
1395
1396           res = CreateProcessW (rundll_path, args,
1397                                 0, 0, FALSE,
1398                                 NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS,
1399                                 0, NULL /* TODO: Should be root */,
1400                                 &si, &pi);
1401           if (res)
1402             address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1403         }
1404     }
1405
1406   release_mutex (autolaunch_mutex);
1407
1408   if (address == NULL)
1409     g_set_error (error,
1410                  G_IO_ERROR,
1411                  G_IO_ERROR_FAILED,
1412                  _("Session dbus not running, and autolaunch failed"));
1413
1414   return address;
1415 }
1416 #endif
1417
1418 /* ---------------------------------------------------------------------------------------------------- */
1419
1420 static gchar *
1421 get_session_address_platform_specific (GError **error)
1422 {
1423   gchar *ret;
1424 #if defined (G_OS_UNIX) || defined(G_OS_WIN32)
1425   /* need to handle OS X in a different way since `dbus-launch --autolaunch' probably won't work there */
1426   ret = get_session_address_dbus_launch (error);
1427 #else
1428   /* TODO: implement for OS X */
1429   ret = NULL;
1430   g_set_error (error,
1431                G_IO_ERROR,
1432                G_IO_ERROR_FAILED,
1433                _("Cannot determine session bus address (not implemented for this OS)"));
1434 #endif
1435   return ret;
1436 }
1437
1438 /* ---------------------------------------------------------------------------------------------------- */
1439
1440 /**
1441  * g_dbus_address_get_for_bus_sync:
1442  * @bus_type: A #GBusType.
1443  * @cancellable: (allow-none): A #GCancellable or %NULL.
1444  * @error: Return location for error or %NULL.
1445  *
1446  * Synchronously looks up the D-Bus address for the well-known message
1447  * bus instance specified by @bus_type. This may involve using various
1448  * platform specific mechanisms.
1449  *
1450  * Returns: A valid D-Bus address string for @bus_type or %NULL if @error is set.
1451  *
1452  * Since: 2.26
1453  */
1454 gchar *
1455 g_dbus_address_get_for_bus_sync (GBusType       bus_type,
1456                                  GCancellable  *cancellable,
1457                                  GError       **error)
1458 {
1459   gchar *ret;
1460   const gchar *starter_bus;
1461   GError *local_error;
1462
1463   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1464
1465   ret = NULL;
1466   local_error = NULL;
1467
1468   if (G_UNLIKELY (_g_dbus_debug_address ()))
1469     {
1470       guint n;
1471       _g_dbus_debug_print_lock ();
1472       g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type `%s'\n",
1473                _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
1474       for (n = 0; n < 3; n++)
1475         {
1476           const gchar *k;
1477           const gchar *v;
1478           switch (n)
1479             {
1480             case 0: k = "DBUS_SESSION_BUS_ADDRESS"; break;
1481             case 1: k = "DBUS_SYSTEM_BUS_ADDRESS"; break;
1482             case 2: k = "DBUS_STARTER_BUS_TYPE"; break;
1483             default: g_assert_not_reached ();
1484             }
1485           v = g_getenv (k);
1486           g_print ("GDBus-debug:Address: env var %s", k);
1487           if (v != NULL)
1488             g_print ("=`%s'\n", v);
1489           else
1490             g_print (" is not set\n");
1491         }
1492       _g_dbus_debug_print_unlock ();
1493     }
1494
1495   switch (bus_type)
1496     {
1497     case G_BUS_TYPE_SYSTEM:
1498       ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
1499       if (ret == NULL)
1500         {
1501           ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
1502         }
1503       break;
1504
1505     case G_BUS_TYPE_SESSION:
1506       ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
1507       if (ret == NULL)
1508         {
1509           ret = get_session_address_platform_specific (&local_error);
1510         }
1511       break;
1512
1513     case G_BUS_TYPE_STARTER:
1514       starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
1515       if (g_strcmp0 (starter_bus, "session") == 0)
1516         {
1517           ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, cancellable, &local_error);
1518           goto out;
1519         }
1520       else if (g_strcmp0 (starter_bus, "system") == 0)
1521         {
1522           ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, cancellable, &local_error);
1523           goto out;
1524         }
1525       else
1526         {
1527           if (starter_bus != NULL)
1528             {
1529               g_set_error (&local_error,
1530                            G_IO_ERROR,
1531                            G_IO_ERROR_FAILED,
1532                            _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
1533                              " - unknown value `%s'"),
1534                            starter_bus);
1535             }
1536           else
1537             {
1538               g_set_error_literal (&local_error,
1539                                    G_IO_ERROR,
1540                                    G_IO_ERROR_FAILED,
1541                                    _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
1542                                      "variable is not set"));
1543             }
1544         }
1545       break;
1546
1547     default:
1548       g_set_error (&local_error,
1549                    G_IO_ERROR,
1550                    G_IO_ERROR_FAILED,
1551                    _("Unknown bus type %d"),
1552                    bus_type);
1553       break;
1554     }
1555
1556  out:
1557   if (G_UNLIKELY (_g_dbus_debug_address ()))
1558     {
1559       _g_dbus_debug_print_lock ();
1560       if (ret != NULL)
1561         {
1562           g_print ("GDBus-debug:Address: Returning address `%s' for bus type `%s'\n",
1563                    ret,
1564                    _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
1565         }
1566       else
1567         {
1568           g_print ("GDBus-debug:Address: Cannot look-up address bus type `%s': %s\n",
1569                    _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type),
1570                    local_error ? local_error->message : "");
1571         }
1572       _g_dbus_debug_print_unlock ();
1573     }
1574
1575   if (local_error != NULL)
1576     g_propagate_error (error, local_error);
1577
1578   return ret;
1579 }