Fix some errors in translated strings
[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 <sys/wait.h>
28
29 #include "gioerror.h"
30 #include "gdbusutils.h"
31 #include "gdbusaddress.h"
32 #include "gdbuserror.h"
33 #include "gioenumtypes.h"
34 #include "gnetworkaddress.h"
35 #include "gsocketclient.h"
36 #include "giostream.h"
37 #include "gasyncresult.h"
38 #include "gsimpleasyncresult.h"
39 #include "gdbusprivate.h"
40
41 #ifdef G_OS_UNIX
42 #include <gio/gunixsocketaddress.h>
43 #endif
44
45 #include "glibintl.h"
46 #include "gioalias.h"
47
48 /**
49  * SECTION:gdbusaddress
50  * @title: D-Bus Addresses
51  * @short_description: D-Bus connection endpoints
52  * @include: gio/gio.h
53  *
54  * Routines for working with D-Bus addresses. A D-Bus address is a string
55  * like "unix:tmpdir=/tmp/my-app-name". The exact format of addresses
56  * is explained in detail in the <link linkend="http://dbus.freedesktop.org/doc/dbus-specification.html&num;addresses">D-Bus specification</link>.
57  */
58
59 static gchar *get_session_address_platform_specific (GError **error);
60
61 /* ---------------------------------------------------------------------------------------------------- */
62
63 /**
64  * g_dbus_is_address:
65  * @string: A string.
66  *
67  * Checks if @string is a D-Bus address.
68  *
69  * This doesn't check if @string is actually supported by #GDBusServer
70  * or #GDBusConnection - use g_dbus_is_supported_address() to do more
71  * checks.
72  *
73  * Returns: %TRUE if @string is a valid D-Bus address, %FALSE otherwise.
74  *
75  * Since: 2.26
76  */
77 gboolean
78 g_dbus_is_address (const gchar *string)
79 {
80   guint n;
81   gchar **a;
82   gboolean ret;
83
84   ret = FALSE;
85
86   g_return_val_if_fail (string != NULL, FALSE);
87
88   a = g_strsplit (string, ";", 0);
89   if (a[0] == NULL)
90     goto out;
91
92   for (n = 0; a[n] != NULL; n++)
93     {
94       if (!_g_dbus_address_parse_entry (a[n],
95                                         NULL,
96                                         NULL,
97                                         NULL))
98         goto out;
99     }
100
101   ret = TRUE;
102
103  out:
104   g_strfreev (a);
105   return ret;
106 }
107
108 static gboolean
109 is_valid_unix (const gchar  *address_entry,
110                GHashTable   *key_value_pairs,
111                GError      **error)
112 {
113   gboolean ret;
114   GList *keys;
115   GList *l;
116   const gchar *path;
117   const gchar *tmpdir;
118   const gchar *abstract;
119
120   ret = FALSE;
121   keys = NULL;
122   path = NULL;
123   tmpdir = NULL;
124   abstract = NULL;
125
126   keys = g_hash_table_get_keys (key_value_pairs);
127   for (l = keys; l != NULL; l = l->next)
128     {
129       const gchar *key = l->data;
130       if (g_strcmp0 (key, "path") == 0)
131         path = g_hash_table_lookup (key_value_pairs, key);
132       else if (g_strcmp0 (key, "tmpdir") == 0)
133         tmpdir = g_hash_table_lookup (key_value_pairs, key);
134       else if (g_strcmp0 (key, "abstract") == 0)
135         abstract = g_hash_table_lookup (key_value_pairs, key);
136       else
137         {
138           g_set_error (error,
139                        G_IO_ERROR,
140                        G_IO_ERROR_INVALID_ARGUMENT,
141                        _("Unsupported key `%s' in address entry `%s'"),
142                        key,
143                        address_entry);
144           goto out;
145         }
146     }
147
148   if (path != NULL)
149     {
150       if (tmpdir != NULL || abstract != NULL)
151         goto meaningless;
152       /* TODO: validate path */
153     }
154   else if (tmpdir != NULL)
155     {
156       if (path != NULL || abstract != NULL)
157         goto meaningless;
158       /* TODO: validate tmpdir */
159     }
160   else if (abstract != NULL)
161     {
162       if (path != NULL || tmpdir != NULL)
163         goto meaningless;
164       /* TODO: validate abstract */
165     }
166   else
167     {
168       g_set_error (error,
169                    G_IO_ERROR,
170                    G_IO_ERROR_INVALID_ARGUMENT,
171                    _("Address `%s' is invalid (need exactly one of path, tmpdir or abstract keys)"),
172                    address_entry);
173       goto out;
174     }
175
176
177   ret= TRUE;
178   goto out;
179
180  meaningless:
181   g_set_error (error,
182                G_IO_ERROR,
183                G_IO_ERROR_INVALID_ARGUMENT,
184                _("Meaningless key/value pair combination in address entry `%s'"),
185                address_entry);
186
187  out:
188   g_list_free (keys);
189
190   return ret;
191 }
192
193 static gboolean
194 is_valid_nonce_tcp (const gchar  *address_entry,
195                     GHashTable   *key_value_pairs,
196                     GError      **error)
197 {
198   gboolean ret;
199   GList *keys;
200   GList *l;
201   const gchar *host;
202   const gchar *port;
203   const gchar *family;
204   const gchar *nonce_file;
205   gint port_num;
206   gchar *endp;
207
208   ret = FALSE;
209   keys = NULL;
210   host = NULL;
211   port = NULL;
212   family = NULL;
213   nonce_file = NULL;
214
215   keys = g_hash_table_get_keys (key_value_pairs);
216   for (l = keys; l != NULL; l = l->next)
217     {
218       const gchar *key = l->data;
219       if (g_strcmp0 (key, "host") == 0)
220         host = g_hash_table_lookup (key_value_pairs, key);
221       else if (g_strcmp0 (key, "port") == 0)
222         port = g_hash_table_lookup (key_value_pairs, key);
223       else if (g_strcmp0 (key, "family") == 0)
224         family = g_hash_table_lookup (key_value_pairs, key);
225       else if (g_strcmp0 (key, "noncefile") == 0)
226         nonce_file = g_hash_table_lookup (key_value_pairs, key);
227       else
228         {
229           g_set_error (error,
230                        G_IO_ERROR,
231                        G_IO_ERROR_INVALID_ARGUMENT,
232                        _("Unsupported key `%s' in address entry `%s'"),
233                        key,
234                        address_entry);
235           goto out;
236         }
237     }
238
239   if (port != NULL)
240     {
241       port_num = strtol (port, &endp, 10);
242       if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
243         {
244           g_set_error (error,
245                        G_IO_ERROR,
246                        G_IO_ERROR_INVALID_ARGUMENT,
247                        _("Error in address `%s' - the port attribute is malformed"),
248                        address_entry);
249           goto out;
250         }
251     }
252
253   if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
254     {
255       g_set_error (error,
256                    G_IO_ERROR,
257                    G_IO_ERROR_INVALID_ARGUMENT,
258                    _("Error in address `%s' - the family attribute is malformed"),
259                    address_entry);
260       goto out;
261     }
262
263   ret= TRUE;
264
265  out:
266   g_list_free (keys);
267
268   return ret;
269 }
270
271 static gboolean
272 is_valid_tcp (const gchar  *address_entry,
273               GHashTable   *key_value_pairs,
274               GError      **error)
275 {
276   gboolean ret;
277   GList *keys;
278   GList *l;
279   const gchar *host;
280   const gchar *port;
281   const gchar *family;
282   gint port_num;
283   gchar *endp;
284
285   ret = FALSE;
286   keys = NULL;
287   host = NULL;
288   port = NULL;
289   family = NULL;
290
291   keys = g_hash_table_get_keys (key_value_pairs);
292   for (l = keys; l != NULL; l = l->next)
293     {
294       const gchar *key = l->data;
295       if (g_strcmp0 (key, "host") == 0)
296         host = g_hash_table_lookup (key_value_pairs, key);
297       else if (g_strcmp0 (key, "port") == 0)
298         port = g_hash_table_lookup (key_value_pairs, key);
299       else if (g_strcmp0 (key, "family") == 0)
300         family = g_hash_table_lookup (key_value_pairs, key);
301       else
302         {
303           g_set_error (error,
304                        G_IO_ERROR,
305                        G_IO_ERROR_INVALID_ARGUMENT,
306                        _("Unsupported key `%s' in address entry `%s'"),
307                        key,
308                        address_entry);
309           goto out;
310         }
311     }
312
313   if (port != NULL)
314     {
315       port_num = strtol (port, &endp, 10);
316       if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
317         {
318           g_set_error (error,
319                        G_IO_ERROR,
320                        G_IO_ERROR_INVALID_ARGUMENT,
321                        _("Error in address `%s' - the port attribute is malformed"),
322                        address_entry);
323           goto out;
324         }
325     }
326
327   if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
328     {
329       g_set_error (error,
330                    G_IO_ERROR,
331                    G_IO_ERROR_INVALID_ARGUMENT,
332                    _("Error in address `%s' - the family attribute is malformed"),
333                    address_entry);
334       goto out;
335     }
336
337   ret= TRUE;
338
339  out:
340   g_list_free (keys);
341
342   return ret;
343 }
344
345 /**
346  * g_dbus_is_supported_address:
347  * @string: A string.
348  * @error: Return location for error or %NULL.
349  *
350  * Like g_dbus_is_address() but also checks if the library suppors the
351  * transports in @string and that key/value pairs for each transport
352  * are valid.
353  *
354  * Returns: %TRUE if @string is a valid D-Bus address that is
355  * supported by this library, %FALSE if @error is set.
356  *
357  * Since: 2.26
358  */
359 gboolean
360 g_dbus_is_supported_address (const gchar  *string,
361                              GError      **error)
362 {
363   guint n;
364   gchar **a;
365   gboolean ret;
366
367   ret = FALSE;
368
369   g_return_val_if_fail (string != NULL, FALSE);
370   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
371
372   a = g_strsplit (string, ";", 0);
373   for (n = 0; a[n] != NULL; n++)
374     {
375       gchar *transport_name;
376       GHashTable *key_value_pairs;
377       gboolean supported;
378
379       if (!_g_dbus_address_parse_entry (a[n],
380                                         &transport_name,
381                                         &key_value_pairs,
382                                         error))
383         goto out;
384
385       supported = FALSE;
386       if (g_strcmp0 (transport_name, "unix") == 0)
387         supported = is_valid_unix (a[n], key_value_pairs, error);
388       else if (g_strcmp0 (transport_name, "tcp") == 0)
389         supported = is_valid_tcp (a[n], key_value_pairs, error);
390       else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
391         supported = is_valid_nonce_tcp (a[n], key_value_pairs, error);
392       else if (g_strcmp0 (a[n], "autolaunch:") == 0)
393         supported = TRUE;
394
395       g_free (transport_name);
396       g_hash_table_unref (key_value_pairs);
397
398       if (!supported)
399         goto out;
400     }
401
402   ret = TRUE;
403
404  out:
405   g_strfreev (a);
406
407   g_assert (ret || (!ret && (error == NULL || *error != NULL)));
408
409   return ret;
410 }
411
412 gboolean
413 _g_dbus_address_parse_entry (const gchar  *address_entry,
414                              gchar       **out_transport_name,
415                              GHashTable  **out_key_value_pairs,
416                              GError      **error)
417 {
418   gboolean ret;
419   GHashTable *key_value_pairs;
420   gchar *transport_name;
421   gchar **kv_pairs;
422   const gchar *s;
423   guint n;
424
425   ret = FALSE;
426   kv_pairs = NULL;
427   transport_name = NULL;
428   key_value_pairs = NULL;
429
430   s = strchr (address_entry, ':');
431   if (s == NULL)
432     {
433       g_set_error (error,
434                    G_IO_ERROR,
435                    G_IO_ERROR_INVALID_ARGUMENT,
436                    _("Address element `%s', does not contain a colon (:)"),
437                    address_entry);
438       goto out;
439     }
440
441   transport_name = g_strndup (address_entry, s - address_entry);
442   key_value_pairs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
443
444   kv_pairs = g_strsplit (s + 1, ",", 0);
445   for (n = 0; kv_pairs != NULL && kv_pairs[n] != NULL; n++)
446     {
447       const gchar *kv_pair = kv_pairs[n];
448       gchar *key;
449       gchar *value;
450
451       s = strchr (kv_pair, '=');
452       if (s == NULL)
453         {
454           g_set_error (error,
455                        G_IO_ERROR,
456                        G_IO_ERROR_INVALID_ARGUMENT,
457                        _("Key/Value pair %d, `%s', in address element `%s', does not contain an equal sign"),
458                        n,
459                        kv_pair,
460                        address_entry);
461           goto out;
462         }
463
464       /* TODO: actually validate that no illegal characters are present before and after then '=' sign */
465       key = g_uri_unescape_segment (kv_pair, s, NULL);
466       value = g_uri_unescape_segment (s + 1, kv_pair + strlen (kv_pair), NULL);
467       g_hash_table_insert (key_value_pairs, key, value);
468     }
469
470   ret = TRUE;
471
472 out:
473   g_strfreev (kv_pairs);
474   if (ret)
475     {
476       if (out_transport_name != NULL)
477         *out_transport_name = transport_name;
478       else
479         g_free (transport_name);
480       if (out_key_value_pairs != NULL)
481         *out_key_value_pairs = key_value_pairs;
482       else if (key_value_pairs != NULL)
483         g_hash_table_unref (key_value_pairs);
484     }
485   else
486     {
487       g_free (transport_name);
488       if (key_value_pairs != NULL)
489         g_hash_table_unref (key_value_pairs);
490     }
491   return ret;
492 }
493
494 /* ---------------------------------------------------------------------------------------------------- */
495
496 static GIOStream *
497 g_dbus_address_try_connect_one (const gchar   *address_entry,
498                                 gchar        **out_guid,
499                                 GCancellable  *cancellable,
500                                 GError       **error);
501
502 /* TODO: Declare an extension point called GDBusTransport (or similar)
503  * and move code below to extensions implementing said extension
504  * point. That way we can implement a D-Bus transport over X11 without
505  * making libgio link to libX11...
506  */
507 static GIOStream *
508 g_dbus_address_connect (const gchar   *address_entry,
509                         const gchar   *transport_name,
510                         GHashTable    *key_value_pairs,
511                         GCancellable  *cancellable,
512                         GError       **error)
513 {
514   GIOStream *ret;
515   GSocketConnectable *connectable;
516   const gchar *nonce_file;
517
518   connectable = NULL;
519   ret = NULL;
520   nonce_file = NULL;
521
522   if (FALSE)
523     {
524     }
525 #ifdef G_OS_UNIX
526   else if (g_strcmp0 (transport_name, "unix") == 0)
527     {
528       const gchar *path;
529       const gchar *abstract;
530       path = g_hash_table_lookup (key_value_pairs, "path");
531       abstract = g_hash_table_lookup (key_value_pairs, "abstract");
532       if ((path == NULL && abstract == NULL) || (path != NULL && abstract != NULL))
533         {
534           g_set_error (error,
535                        G_IO_ERROR,
536                        G_IO_ERROR_INVALID_ARGUMENT,
537                        _("Error in address `%s' - the unix transport requires exactly one of the "
538                          "keys `path' or `abstract' to be set"),
539                        address_entry);
540         }
541       else if (path != NULL)
542         {
543           connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path));
544         }
545       else if (abstract != NULL)
546         {
547           connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract,
548                                                                                    -1,
549                                                                                    G_UNIX_SOCKET_ADDRESS_ABSTRACT));
550         }
551       else
552         {
553           g_assert_not_reached ();
554         }
555     }
556 #endif
557   else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0)
558     {
559       const gchar *s;
560       const gchar *host;
561       guint port;
562       gchar *endp;
563       gboolean is_nonce;
564
565       is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0);
566
567       host = g_hash_table_lookup (key_value_pairs, "host");
568       if (host == NULL)
569         {
570           g_set_error (error,
571                        G_IO_ERROR,
572                        G_IO_ERROR_INVALID_ARGUMENT,
573                        _("Error in address `%s' - the host attribute is missing or malformed"),
574                        address_entry);
575           goto out;
576         }
577
578       s = g_hash_table_lookup (key_value_pairs, "port");
579       if (s == NULL)
580         s = "0";
581       port = strtol (s, &endp, 10);
582       if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536)
583         {
584           g_set_error (error,
585                        G_IO_ERROR,
586                        G_IO_ERROR_INVALID_ARGUMENT,
587                        _("Error in address `%s' - the port attribute is missing or malformed"),
588                        address_entry);
589           goto out;
590         }
591
592
593       if (is_nonce)
594         {
595           nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
596           if (nonce_file == NULL)
597             {
598               g_set_error (error,
599                            G_IO_ERROR,
600                            G_IO_ERROR_INVALID_ARGUMENT,
601                            _("Error in address `%s' - the noncefile attribute is missing or malformed"),
602                            address_entry);
603               goto out;
604             }
605         }
606
607       /* TODO: deal with family */
608       connectable = g_network_address_new (host, port);
609     }
610   else if (g_strcmp0 (address_entry, "autolaunch:") == 0)
611     {
612       gchar *autolaunch_address;
613       autolaunch_address = get_session_address_platform_specific (error);
614       if (autolaunch_address != NULL)
615         {
616           ret = g_dbus_address_try_connect_one (autolaunch_address, NULL, cancellable, error);
617           g_free (autolaunch_address);
618           goto out;
619         }
620       else
621         {
622           g_prefix_error (error, _("Error auto-launching: "));
623         }
624     }
625   else
626     {
627       g_set_error (error,
628                    G_IO_ERROR,
629                    G_IO_ERROR_INVALID_ARGUMENT,
630                    _("Unknown or unsupported transport `%s' for address `%s'"),
631                    transport_name,
632                    address_entry);
633     }
634
635   if (connectable != NULL)
636     {
637       GSocketClient *client;
638       GSocketConnection *connection;
639
640       g_assert (ret == NULL);
641       client = g_socket_client_new ();
642       connection = g_socket_client_connect (client,
643                                             connectable,
644                                             cancellable,
645                                             error);
646       g_object_unref (connectable);
647       g_object_unref (client);
648       if (connection == NULL)
649         goto out;
650
651       ret = G_IO_STREAM (connection);
652
653       if (nonce_file != NULL)
654         {
655           gchar *nonce_contents;
656           gsize nonce_length;
657
658           /* TODO: too dangerous to read the entire file? (think denial-of-service etc.) */
659           if (!g_file_get_contents (nonce_file,
660                                     &nonce_contents,
661                                     &nonce_length,
662                                     error))
663             {
664               g_prefix_error (error, _("Error reading nonce file `%s':"), nonce_file);
665               g_object_unref (ret);
666               ret = NULL;
667               goto out;
668             }
669
670           if (nonce_length != 16)
671             {
672               /* G_GSIZE_FORMAT doesn't work with gettext, so we use %lu */
673               g_set_error (error,
674                            G_IO_ERROR,
675                            G_IO_ERROR_INVALID_ARGUMENT,
676                            _("The nonce-file `%s' was %lu bytes. Expected 16 bytes."),
677                            nonce_file,
678                            nonce_length);
679               g_free (nonce_contents);
680               g_object_unref (ret);
681               ret = NULL;
682               goto out;
683             }
684
685           if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret),
686                                           nonce_contents,
687                                           nonce_length,
688                                           NULL,
689                                           cancellable,
690                                           error))
691             {
692               g_prefix_error (error, _("Error write contents of nonce file `%s' to stream:"), nonce_file);
693               g_object_unref (ret);
694               ret = NULL;
695               g_free (nonce_contents);
696               goto out;
697             }
698           g_free (nonce_contents);
699         }
700     }
701
702  out:
703
704   return ret;
705 }
706
707 static GIOStream *
708 g_dbus_address_try_connect_one (const gchar   *address_entry,
709                                 gchar        **out_guid,
710                                 GCancellable  *cancellable,
711                                 GError       **error)
712 {
713   GIOStream *ret;
714   GHashTable *key_value_pairs;
715   gchar *transport_name;
716   const gchar *guid;
717
718   ret = NULL;
719   transport_name = NULL;
720   key_value_pairs = NULL;
721
722   if (!_g_dbus_address_parse_entry (address_entry,
723                                     &transport_name,
724                                     &key_value_pairs,
725                                     error))
726     goto out;
727
728   ret = g_dbus_address_connect (address_entry,
729                                 transport_name,
730                                 key_value_pairs,
731                                 cancellable,
732                                 error);
733   if (ret == NULL)
734     goto out;
735
736   /* TODO: validate that guid is of correct format */
737   guid = g_hash_table_lookup (key_value_pairs, "guid");
738   if (guid != NULL && out_guid != NULL)
739     *out_guid = g_strdup (guid);
740
741 out:
742   g_free (transport_name);
743   if (key_value_pairs != NULL)
744     g_hash_table_unref (key_value_pairs);
745   return ret;
746 }
747
748
749 /* ---------------------------------------------------------------------------------------------------- */
750
751 typedef struct {
752   gchar *address;
753   GIOStream *stream;
754   gchar *guid;
755 } GetStreamData;
756
757 static void
758 get_stream_data_free (GetStreamData *data)
759 {
760   g_free (data->address);
761   if (data->stream != NULL)
762     g_object_unref (data->stream);
763   g_free (data->guid);
764   g_free (data);
765 }
766
767 static void
768 get_stream_thread_func (GSimpleAsyncResult *res,
769                         GObject            *object,
770                         GCancellable       *cancellable)
771 {
772   GetStreamData *data;
773   GError *error;
774
775   data = g_simple_async_result_get_op_res_gpointer (res);
776
777   error = NULL;
778   data->stream = g_dbus_address_get_stream_sync (data->address,
779                                                  &data->guid,
780                                                  cancellable,
781                                                  &error);
782   if (data->stream == NULL)
783     {
784       g_simple_async_result_set_from_error (res, error);
785       g_error_free (error);
786     }
787 }
788
789 /**
790  * g_dbus_address_get_stream:
791  * @address: A valid D-Bus address.
792  * @cancellable: A #GCancellable or %NULL.
793  * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
794  * @user_data: Data to pass to @callback.
795  *
796  * Asynchronously connects to an endpoint specified by @address and
797  * sets up the connection so it is in a state to run the client-side
798  * of the D-Bus authentication conversation.
799  *
800  * When the operation is finished, @callback will be invoked. You can
801  * then call g_dbus_address_get_stream_finish() to get the result of
802  * the operation.
803  *
804  * This is an asynchronous failable function. See
805  * g_dbus_address_get_stream_sync() for the synchronous version.
806  *
807  * Since: 2.26
808  */
809 void
810 g_dbus_address_get_stream (const gchar         *address,
811                            GCancellable        *cancellable,
812                            GAsyncReadyCallback  callback,
813                            gpointer             user_data)
814 {
815   GSimpleAsyncResult *res;
816   GetStreamData *data;
817
818   g_return_if_fail (address != NULL);
819
820   res = g_simple_async_result_new (NULL,
821                                    callback,
822                                    user_data,
823                                    g_dbus_address_get_stream);
824   data = g_new0 (GetStreamData, 1);
825   data->address = g_strdup (address);
826   g_simple_async_result_set_op_res_gpointer (res,
827                                              data,
828                                              (GDestroyNotify) get_stream_data_free);
829   g_simple_async_result_run_in_thread (res,
830                                        get_stream_thread_func,
831                                        G_PRIORITY_DEFAULT,
832                                        cancellable);
833   g_object_unref (res);
834 }
835
836 /**
837  * g_dbus_address_get_stream_finish:
838  * @res: A #GAsyncResult obtained from the GAsyncReadyCallback passed to g_dbus_address_get_stream().
839  * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
840  * @error: Return location for error or %NULL.
841  *
842  * Finishes an operation started with g_dbus_address_get_stream().
843  *
844  * Returns: A #GIOStream or %NULL if @error is set.
845  *
846  * Since: 2.26
847  */
848 GIOStream *
849 g_dbus_address_get_stream_finish (GAsyncResult        *res,
850                                   gchar              **out_guid,
851                                   GError             **error)
852 {
853   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
854   GetStreamData *data;
855   GIOStream *ret;
856
857   g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
858   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
859
860   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_address_get_stream);
861
862   ret = NULL;
863
864   data = g_simple_async_result_get_op_res_gpointer (simple);
865   if (g_simple_async_result_propagate_error (simple, error))
866     goto out;
867
868   ret = g_object_ref (data->stream);
869   if (out_guid != NULL)
870     *out_guid = g_strdup (data->guid);
871
872  out:
873   return ret;
874 }
875
876 /**
877  * g_dbus_address_get_stream_sync:
878  * @address: A valid D-Bus address.
879  * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
880  * @cancellable: A #GCancellable or %NULL.
881  * @error: Return location for error or %NULL.
882  *
883  * Synchronously connects to an endpoint specified by @address and
884  * sets up the connection so it is in a state to run the client-side
885  * of the D-Bus authentication conversation.
886  *
887  * This is a synchronous failable function. See
888  * g_dbus_address_get_stream() for the asynchronous version.
889  *
890  * Returns: A #GIOStream or %NULL if @error is set.
891  *
892  * Since: 2.26
893  */
894 GIOStream *
895 g_dbus_address_get_stream_sync (const gchar   *address,
896                                 gchar        **out_guid,
897                                 GCancellable  *cancellable,
898                                 GError       **error)
899 {
900   GIOStream *ret;
901   gchar **addr_array;
902   guint n;
903   GError *last_error;
904
905   g_return_val_if_fail (address != NULL, NULL);
906   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
907
908   ret = NULL;
909   last_error = NULL;
910
911   addr_array = g_strsplit (address, ";", 0);
912   if (addr_array[0] == NULL)
913     {
914       last_error = g_error_new_literal (G_IO_ERROR,
915                                         G_IO_ERROR_INVALID_ARGUMENT,
916                                         _("The given address is empty"));
917       goto out;
918     }
919
920   for (n = 0; addr_array != NULL && addr_array[n] != NULL; n++)
921     {
922       const gchar *addr = addr_array[n];
923       GError *this_error;
924
925       this_error = NULL;
926       ret = g_dbus_address_try_connect_one (addr,
927                                             out_guid,
928                                             cancellable,
929                                             &this_error);
930       if (ret != NULL)
931         {
932           goto out;
933         }
934       else
935         {
936           g_assert (this_error != NULL);
937           if (last_error != NULL)
938             g_error_free (last_error);
939           last_error = this_error;
940         }
941     }
942
943  out:
944   if (ret != NULL)
945     {
946       if (last_error != NULL)
947         g_error_free (last_error);
948     }
949   else
950     {
951       g_assert (last_error != NULL);
952       g_propagate_error (error, last_error);
953     }
954
955   g_strfreev (addr_array);
956   return ret;
957 }
958
959 /* ---------------------------------------------------------------------------------------------------- */
960
961 #ifdef G_OS_UNIX
962 static gchar *
963 get_session_address_dbus_launch (GError **error)
964 {
965   gchar *ret;
966   gchar *machine_id;
967   gchar *command_line;
968   gchar *launch_stdout;
969   gchar *launch_stderr;
970   gint exit_status;
971   gchar *old_dbus_verbose;
972   gboolean restore_dbus_verbose;
973
974   ret = NULL;
975   machine_id = NULL;
976   command_line = NULL;
977   launch_stdout = NULL;
978   launch_stderr = NULL;
979   restore_dbus_verbose = FALSE;
980   old_dbus_verbose = NULL;
981
982   machine_id = _g_dbus_get_machine_id (error);
983   if (machine_id == NULL)
984     {
985       g_prefix_error (error, _("Cannot spawn a message bus without a machine-id: "));
986       goto out;
987     }
988
989   /* We're using private libdbus facilities here. When everything
990    * (X11, Mac OS X, Windows) is spec'ed out correctly (not even the
991    * X11 property is correctly documented right now) we should
992    * consider using the spec instead of dbus-launch.
993    *
994    *   --autolaunch=MACHINEID
995    *          This option implies that dbus-launch should scan  for  a  previ‐
996    *          ously-started  session  and  reuse the values found there. If no
997    *          session is found, it will start a new session. The  --exit-with-
998    *          session option is implied if --autolaunch is given.  This option
999    *          is for the exclusive use of libdbus, you do not want to  use  it
1000    *          manually. It may change in the future.
1001    */
1002
1003   /* TODO: maybe provide a variable for where to look for the dbus-launch binary? */
1004   command_line = g_strdup_printf ("dbus-launch --autolaunch=%s --binary-syntax --close-stderr", machine_id);
1005
1006   if (G_UNLIKELY (_g_dbus_debug_address ()))
1007     {
1008       _g_dbus_debug_print_lock ();
1009       g_print ("GDBus-debug:Address: Running `%s' to get bus address (possibly autolaunching)\n", command_line);
1010       old_dbus_verbose = g_strdup (g_getenv ("DBUS_VERBOSE"));
1011       restore_dbus_verbose = TRUE;
1012       g_setenv ("DBUS_VERBOSE", "1", TRUE);
1013       _g_dbus_debug_print_unlock ();
1014     }
1015
1016   if (!g_spawn_command_line_sync (command_line,
1017                                   &launch_stdout,
1018                                   &launch_stderr,
1019                                   &exit_status,
1020                                   error))
1021     {
1022       g_prefix_error (error, _("Error spawning command line `%s': "), command_line);
1023       goto out;
1024     }
1025
1026   if (!WIFEXITED (exit_status))
1027     {
1028       gchar *escaped_stderr;
1029       escaped_stderr = g_strescape (launch_stderr, "");
1030       g_set_error (error,
1031                    G_IO_ERROR,
1032                    G_IO_ERROR_FAILED,
1033                    _("Abnormal program termination spawning command line `%s': %s"),
1034                    command_line,
1035                    escaped_stderr);
1036       g_free (escaped_stderr);
1037       goto out;
1038     }
1039
1040   if (WEXITSTATUS (exit_status) != 0)
1041     {
1042       gchar *escaped_stderr;
1043       escaped_stderr = g_strescape (launch_stderr, "");
1044       g_set_error (error,
1045                    G_IO_ERROR,
1046                    G_IO_ERROR_FAILED,
1047                    _("Command line `%s' exited with non-zero exit status %d: %s"),
1048                    command_line,
1049                    WEXITSTATUS (exit_status),
1050                    escaped_stderr);
1051       g_free (escaped_stderr);
1052       goto out;
1053     }
1054
1055   /* From the dbus-launch(1) man page:
1056    *
1057    *   --binary-syntax Write to stdout a nul-terminated bus address,
1058    *   then the bus PID as a binary integer of size sizeof(pid_t),
1059    *   then the bus X window ID as a binary integer of size
1060    *   sizeof(long).  Integers are in the machine's byte order, not
1061    *   network byte order or any other canonical byte order.
1062    */
1063   ret = g_strdup (launch_stdout);
1064
1065  out:
1066   if (G_UNLIKELY (_g_dbus_debug_address ()))
1067     {
1068       gchar *s;
1069       _g_dbus_debug_print_lock ();
1070       g_print ("GDBus-debug:Address: dbus-launch output:");
1071       if (launch_stdout != NULL)
1072         {
1073           s = _g_dbus_hexdump (launch_stdout, strlen (launch_stdout) + 1 + sizeof (pid_t) + sizeof (long), 2);
1074           g_print ("\n%s", s);
1075           g_free (s);
1076         }
1077       else
1078         {
1079           g_print (" (none)\n");
1080         }
1081       g_print ("GDBus-debug:Address: dbus-launch stderr output:");
1082       if (launch_stderr != NULL)
1083         g_print ("\n%s", launch_stderr);
1084       else
1085         g_print (" (none)\n");
1086       _g_dbus_debug_print_unlock ();
1087     }
1088
1089   g_free (machine_id);
1090   g_free (command_line);
1091   g_free (launch_stdout);
1092   g_free (launch_stderr);
1093   if (G_UNLIKELY (restore_dbus_verbose))
1094     {
1095       if (old_dbus_verbose != NULL)
1096         g_setenv ("DBUS_VERBOSE", old_dbus_verbose, TRUE);
1097       else
1098         g_unsetenv ("DBUS_VERBOSE");
1099     }
1100   g_free (old_dbus_verbose);
1101   return ret;
1102 }
1103 #endif
1104
1105 /* ---------------------------------------------------------------------------------------------------- */
1106
1107 /* TODO: implement for UNIX, Win32 and OS X */
1108 static gchar *
1109 get_session_address_platform_specific (GError **error)
1110 {
1111   gchar *ret;
1112 #ifdef G_OS_UNIX
1113   /* need to handle OS X in a different way since `dbus-launch --autolaunch' probably won't work there */
1114   ret = get_session_address_dbus_launch (error);
1115 #else
1116   ret = NULL;
1117   g_set_error (error,
1118                G_IO_ERROR,
1119                G_IO_ERROR_FAILED,
1120                _("Cannot determine session bus address (not implemented for this OS)"));
1121 #endif
1122   return ret;
1123 }
1124
1125 /* ---------------------------------------------------------------------------------------------------- */
1126
1127 /**
1128  * g_dbus_address_get_for_bus_sync:
1129  * @bus_type: A #GBusType.
1130  * @cancellable: A #GCancellable or %NULL.
1131  * @error: Return location for error or %NULL.
1132  *
1133  * Synchronously looks up the D-Bus address for the well-known message
1134  * bus instance specified by @bus_type. This may involve using various
1135  * platform specific mechanisms.
1136  *
1137  * Returns: A valid D-Bus address string for @bus_type or %NULL if @error is set.
1138  *
1139  * Since: 2.26
1140  */
1141 gchar *
1142 g_dbus_address_get_for_bus_sync (GBusType       bus_type,
1143                                  GCancellable  *cancellable,
1144                                  GError       **error)
1145 {
1146   gchar *ret;
1147   const gchar *starter_bus;
1148   GError *local_error;
1149
1150   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1151
1152   ret = NULL;
1153   local_error = NULL;
1154
1155   if (G_UNLIKELY (_g_dbus_debug_address ()))
1156     {
1157       guint n;
1158       _g_dbus_debug_print_lock ();
1159       g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type `%s'\n",
1160                _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
1161       for (n = 0; n < 3; n++)
1162         {
1163           const gchar *k;
1164           const gchar *v;
1165           switch (n)
1166             {
1167             case 0: k = "DBUS_SESSION_BUS_ADDRESS"; break;
1168             case 1: k = "DBUS_SYSTEM_BUS_ADDRESS"; break;
1169             case 2: k = "DBUS_STARTER_BUS_TYPE"; break;
1170             default: g_assert_not_reached ();
1171             }
1172           v = g_getenv (k);
1173           g_print ("GDBus-debug:Address: env var %s", k);
1174           if (v != NULL)
1175             g_print ("=`%s'\n", v);
1176           else
1177             g_print (" is not set\n");
1178         }
1179       _g_dbus_debug_print_unlock ();
1180     }
1181
1182   switch (bus_type)
1183     {
1184     case G_BUS_TYPE_SYSTEM:
1185       ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
1186       if (ret == NULL)
1187         {
1188           ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
1189         }
1190       break;
1191
1192     case G_BUS_TYPE_SESSION:
1193       ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
1194       if (ret == NULL)
1195         {
1196           ret = get_session_address_platform_specific (&local_error);
1197         }
1198       break;
1199
1200     case G_BUS_TYPE_STARTER:
1201       starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
1202       if (g_strcmp0 (starter_bus, "session") == 0)
1203         {
1204           ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, cancellable, &local_error);
1205           goto out;
1206         }
1207       else if (g_strcmp0 (starter_bus, "system") == 0)
1208         {
1209           ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, cancellable, &local_error);
1210           goto out;
1211         }
1212       else
1213         {
1214           if (starter_bus != NULL)
1215             {
1216               g_set_error (&local_error,
1217                            G_IO_ERROR,
1218                            G_IO_ERROR_FAILED,
1219                            _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
1220                              " - unknown value `%s'"),
1221                            starter_bus);
1222             }
1223           else
1224             {
1225               g_set_error_literal (&local_error,
1226                                    G_IO_ERROR,
1227                                    G_IO_ERROR_FAILED,
1228                                    _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
1229                                      "variable is not set"));
1230             }
1231         }
1232       break;
1233
1234     default:
1235       g_set_error (&local_error,
1236                    G_IO_ERROR,
1237                    G_IO_ERROR_FAILED,
1238                    _("Unknown bus type %d"),
1239                    bus_type);
1240       break;
1241     }
1242
1243  out:
1244   if (G_UNLIKELY (_g_dbus_debug_address ()))
1245     {
1246       _g_dbus_debug_print_lock ();
1247       if (ret != NULL)
1248         {
1249           g_print ("GDBus-debug:Address: Returning address `%s' for bus type `%s'\n",
1250                    ret,
1251                    _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
1252         }
1253       else
1254         {
1255           g_print ("GDBus-debug:Address: Cannot look-up address bus type `%s': %s\n",
1256                    _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type),
1257                    local_error->message);
1258         }
1259       _g_dbus_debug_print_unlock ();
1260     }
1261
1262   if (local_error != NULL)
1263     g_propagate_error (error, local_error);
1264
1265   return ret;
1266 }
1267
1268 #define __G_DBUS_ADDRESS_C__
1269 #include "gioaliasdef.c"