1 /*
2 * dbus.c - Source for D-Bus utilities
3 *
4 * Copyright (C) 2005-2008 Collabora Ltd. <http://www.collabora.co.uk/>
5 * Copyright (C) 2005-2008 Nokia Corporation
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /**
23 * SECTION:dbus
24 * @title: D-Bus utilities
25 * @short_description: some D-Bus utility functions
26 *
27 * D-Bus utility functions used in telepathy-glib.
28 */
29
30 /**
31 * SECTION:asv
32 * @title: Manipulating a{sv} mappings
33 * @short_description: Functions to manipulate mappings from string to
34 * variant, as represented in dbus-glib by a #GHashTable from string
35 * to #GValue
36 *
37 * Mappings from string to variant (D-Bus signature a{sv}) are commonly used
38 * to provide extensibility, but in dbus-glib they're somewhat awkward to deal
39 * with.
40 *
41 * These functions provide convenient access to the values in such
42 * a mapping.
43 *
44 * They also work around the fact that none of the #GHashTable public API
45 * takes a const pointer to a #GHashTable, even the read-only methods that
46 * logically ought to.
47 *
48 * Parts of telepathy-glib return const pointers to #GHashTable, to encourage
49 * the use of this API.
50 *
51 * Since: 0.7.9
52 */
53
54 #include "config.h"
55
56 #include <telepathy-glib/dbus.h>
57 #include <telepathy-glib/dbus-internal.h>
58
59 #include <stdlib.h>
60 #include <string.h>
61
62 #include <dbus/dbus.h>
63
64 #include <gobject/gvaluecollector.h>
65
66 #include <telepathy-glib/errors.h>
67 #include <telepathy-glib/gtypes.h>
68 #include <telepathy-glib/util.h>
69
70 #define DEBUG_FLAG TP_DEBUG_MISC
71 #include "debug-internal.h"
72
73 /**
74 * tp_asv_size: (skip)
75 * @asv: a GHashTable
76 *
77 * Return the size of @asv as if via g_hash_table_size().
78 *
79 * The only difference is that this version takes a const #GHashTable and
80 * casts it.
81 *
82 * Since: 0.7.12
83 */
84 /* (#define + static inline in dbus.h) */
85
86 /**
87 * tp_dbus_g_method_return_not_implemented: (skip)
88 * @context: The D-Bus method invocation context
89 *
90 * Return the Telepathy error NotImplemented from the method invocation
91 * given by @context.
92 */
93 void
tp_dbus_g_method_return_not_implemented(DBusGMethodInvocation * context)94 tp_dbus_g_method_return_not_implemented (DBusGMethodInvocation *context)
95 {
96 GError e = { TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Not implemented" };
97
98 dbus_g_method_return_error (context, &e);
99 }
100
101 DBusGConnection *
_tp_dbus_starter_bus_conn(GError ** error)102 _tp_dbus_starter_bus_conn (GError **error)
103 {
104 static DBusGConnection *starter_bus = NULL;
105
106 if (starter_bus == NULL)
107 {
108 starter_bus = dbus_g_bus_get (DBUS_BUS_STARTER, error);
109 }
110
111 return starter_bus;
112 }
113
114 /**
115 * tp_get_bus: (skip)
116 *
117 * Returns a connection to the D-Bus daemon on which this process was
118 * activated if it was launched by D-Bus service activation, or the session
119 * bus otherwise.
120 *
121 * If dbus_g_bus_get() fails, exit with error code 1.
122 *
123 * Note that this function is not suitable for use in applications which can
124 * be useful even in the absence of D-Bus - it is designed for use in
125 * connection managers, which are not at all useful without a D-Bus
126 * connection. See <https://bugs.freedesktop.org/show_bug.cgi?id=18832>.
127 * Most processes should use tp_dbus_daemon_dup() instead.
128 *
129 * Returns: a connection to the starter or session D-Bus daemon.
130 */
131 DBusGConnection *
tp_get_bus(void)132 tp_get_bus (void)
133 {
134 GError *error = NULL;
135 DBusGConnection *bus = _tp_dbus_starter_bus_conn (&error);
136
137 if (bus == NULL)
138 {
139 WARNING ("Failed to connect to starter bus: %s", error->message);
140 exit (1);
141 }
142
143 return bus;
144 }
145
146 /**
147 * tp_get_bus_proxy: (skip)
148 *
149 * Return a #DBusGProxy for the bus daemon object. The same caveats as for
150 * tp_get_bus() apply.
151 *
152 * Returns: a proxy for the bus daemon object on the starter or session bus.
153 *
154 * Deprecated: 0.7.26: Use tp_dbus_daemon_dup() in new code.
155 */
156 DBusGProxy *
tp_get_bus_proxy(void)157 tp_get_bus_proxy (void)
158 {
159 static DBusGProxy *bus_proxy = NULL;
160
161 if (bus_proxy == NULL)
162 {
163 GError *error = NULL;
164 DBusGConnection *bus = _tp_dbus_starter_bus_conn (&error);
165
166 if (bus == NULL)
167 {
168 WARNING ("Failed to connect to starter bus: %s", error->message);
169 exit (1);
170 }
171
172 bus_proxy = dbus_g_proxy_new_for_name (bus,
173 "org.freedesktop.DBus",
174 "/org/freedesktop/DBus",
175 "org.freedesktop.DBus");
176
177 if (bus_proxy == NULL)
178 ERROR ("Failed to get proxy object for bus.");
179 }
180
181 return bus_proxy;
182 }
183
184 /**
185 * TpDBusNameType:
186 * @TP_DBUS_NAME_TYPE_UNIQUE: accept unique names like :1.123
187 * (not including the name of the bus daemon itself)
188 * @TP_DBUS_NAME_TYPE_WELL_KNOWN: accept well-known names like
189 * com.example.Service (not including the name of the bus daemon itself)
190 * @TP_DBUS_NAME_TYPE_BUS_DAEMON: accept the name of the bus daemon
191 * itself, which has the syntax of a well-known name, but behaves like a
192 * unique name
193 * @TP_DBUS_NAME_TYPE_NOT_BUS_DAEMON: accept either unique or well-known
194 * names, but not the bus daemon
195 * @TP_DBUS_NAME_TYPE_ANY: accept any of the above
196 *
197 * A set of flags indicating which D-Bus bus names are acceptable.
198 * They can be combined with the bitwise-or operator to accept multiple
199 * types. %TP_DBUS_NAME_TYPE_NOT_BUS_DAEMON and %TP_DBUS_NAME_TYPE_ANY are
200 * the bitwise-or of other appropriate types, for convenience.
201 *
202 * Since 0.11.5, there is a corresponding #GFlagsClass type,
203 * %TP_TYPE_DBUS_NAME_TYPE.
204 *
205 * Since: 0.7.1
206 */
207
208 /**
209 * TP_TYPE_DBUS_NAME_TYPE:
210 *
211 * The #GFlagsClass type of a #TpDBusNameType or a set of name types.
212 *
213 * Since: 0.11.5
214 */
215
216 /**
217 * tp_dbus_check_valid_bus_name:
218 * @name: a possible bus name
219 * @allow_types: some combination of %TP_DBUS_NAME_TYPE_UNIQUE,
220 * %TP_DBUS_NAME_TYPE_WELL_KNOWN or %TP_DBUS_NAME_TYPE_BUS_DAEMON
221 * (often this will be %TP_DBUS_NAME_TYPE_NOT_BUS_DAEMON or
222 * %TP_DBUS_NAME_TYPE_ANY)
223 * @error: used to raise %TP_DBUS_ERROR_INVALID_BUS_NAME if %FALSE is returned
224 *
225 * Check that the given string is a valid D-Bus bus name of an appropriate
226 * type.
227 *
228 * Returns: %TRUE if @name is valid
229 *
230 * Since: 0.7.1
231 */
232 gboolean
tp_dbus_check_valid_bus_name(const gchar * name,TpDBusNameType allow_types,GError ** error)233 tp_dbus_check_valid_bus_name (const gchar *name,
234 TpDBusNameType allow_types,
235 GError **error)
236 {
237 gboolean dot = FALSE;
238 gboolean unique;
239 gchar last;
240 const gchar *ptr;
241
242 g_return_val_if_fail (name != NULL, FALSE);
243
244 if (name[0] == '\0')
245 {
246 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_BUS_NAME,
247 "The empty string is not a valid bus name");
248 return FALSE;
249 }
250
251 if (!tp_strdiff (name, DBUS_SERVICE_DBUS))
252 {
253 if (allow_types & TP_DBUS_NAME_TYPE_BUS_DAEMON)
254 return TRUE;
255
256 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_BUS_NAME,
257 "The D-Bus daemon's bus name is not acceptable here");
258 return FALSE;
259 }
260
261 unique = (name[0] == ':');
262 if (unique && (allow_types & TP_DBUS_NAME_TYPE_UNIQUE) == 0)
263 {
264 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_BUS_NAME,
265 "A well-known bus name not starting with ':'%s is required",
266 allow_types & TP_DBUS_NAME_TYPE_BUS_DAEMON
267 ? " (or the bus daemon itself)"
268 : "");
269 return FALSE;
270 }
271
272 if (!unique && (allow_types & TP_DBUS_NAME_TYPE_WELL_KNOWN) == 0)
273 {
274 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_BUS_NAME,
275 "A unique bus name starting with ':'%s is required",
276 allow_types & TP_DBUS_NAME_TYPE_BUS_DAEMON
277 ? " (or the bus daemon itself)"
278 : "");
279 return FALSE;
280 }
281
282 if (strlen (name) > 255)
283 {
284 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_BUS_NAME,
285 "Invalid bus name: too long (> 255 characters)");
286 return FALSE;
287 }
288
289 last = '\0';
290
291 for (ptr = name + (unique ? 1 : 0); *ptr != '\0'; ptr++)
292 {
293 if (*ptr == '.')
294 {
295 dot = TRUE;
296
297 if (last == '.')
298 {
299 g_set_error (error, TP_DBUS_ERRORS,
300 TP_DBUS_ERROR_INVALID_BUS_NAME,
301 "Invalid bus name '%s': contains '..'", name);
302 return FALSE;
303 }
304 else if (last == '\0')
305 {
306 g_set_error (error, TP_DBUS_ERRORS,
307 TP_DBUS_ERROR_INVALID_BUS_NAME,
308 "Invalid bus name '%s': must not start with '.'", name);
309 return FALSE;
310 }
311 }
312 else if (g_ascii_isdigit (*ptr))
313 {
314 if (!unique)
315 {
316 if (last == '.')
317 {
318 g_set_error (error, TP_DBUS_ERRORS,
319 TP_DBUS_ERROR_INVALID_BUS_NAME,
320 "Invalid bus name '%s': a digit may not follow '.' "
321 "except in a unique name starting with ':'", name);
322 return FALSE;
323 }
324 else if (last == '\0')
325 {
326 g_set_error (error, TP_DBUS_ERRORS,
327 TP_DBUS_ERROR_INVALID_BUS_NAME,
328 "Invalid bus name '%s': must not start with a digit",
329 name);
330 return FALSE;
331 }
332 }
333 }
334 else if (!g_ascii_isalpha (*ptr) && *ptr != '_' && *ptr != '-')
335 {
336 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_BUS_NAME,
337 "Invalid bus name '%s': contains invalid character '%c'",
338 name, *ptr);
339 return FALSE;
340 }
341
342 last = *ptr;
343 }
344
345 if (last == '.')
346 {
347 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_BUS_NAME,
348 "Invalid bus name '%s': must not end with '.'", name);
349 return FALSE;
350 }
351
352 if (!dot)
353 {
354 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_BUS_NAME,
355 "Invalid bus name '%s': must contain '.'", name);
356 return FALSE;
357 }
358
359 return TRUE;
360 }
361
362 /**
363 * tp_dbus_check_valid_interface_name:
364 * @name: a possible interface name
365 * @error: used to raise %TP_DBUS_ERROR_INVALID_INTERFACE_NAME if %FALSE is
366 * returned
367 *
368 * Check that the given string is a valid D-Bus interface name. This is
369 * also appropriate to use to check for valid error names.
370 *
371 * Since GIO 2.26, g_dbus_is_interface_name() should always return the same
372 * thing, although the GLib function does not raise an error explaining why
373 * the interface name is incorrect.
374 *
375 * Returns: %TRUE if @name is valid
376 *
377 * Since: 0.7.1
378 */
379 gboolean
tp_dbus_check_valid_interface_name(const gchar * name,GError ** error)380 tp_dbus_check_valid_interface_name (const gchar *name,
381 GError **error)
382 {
383 gboolean dot = FALSE;
384 gchar last;
385 const gchar *ptr;
386
387 g_return_val_if_fail (name != NULL, FALSE);
388
389 if (name[0] == '\0')
390 {
391 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_INTERFACE_NAME,
392 "The empty string is not a valid interface name");
393 return FALSE;
394 }
395
396 if (strlen (name) > 255)
397 {
398 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_INTERFACE_NAME,
399 "Invalid interface name: too long (> 255 characters)");
400 return FALSE;
401 }
402
403 last = '\0';
404
405 for (ptr = name; *ptr != '\0'; ptr++)
406 {
407 if (*ptr == '.')
408 {
409 dot = TRUE;
410
411 if (last == '.')
412 {
413 g_set_error (error, TP_DBUS_ERRORS,
414 TP_DBUS_ERROR_INVALID_INTERFACE_NAME,
415 "Invalid interface name '%s': contains '..'", name);
416 return FALSE;
417 }
418 else if (last == '\0')
419 {
420 g_set_error (error, TP_DBUS_ERRORS,
421 TP_DBUS_ERROR_INVALID_INTERFACE_NAME,
422 "Invalid interface name '%s': must not start with '.'",
423 name);
424 return FALSE;
425 }
426 }
427 else if (g_ascii_isdigit (*ptr))
428 {
429 if (last == '\0')
430 {
431 g_set_error (error, TP_DBUS_ERRORS,
432 TP_DBUS_ERROR_INVALID_INTERFACE_NAME,
433 "Invalid interface name '%s': must not start with a digit",
434 name);
435 return FALSE;
436 }
437 else if (last == '.')
438 {
439 g_set_error (error, TP_DBUS_ERRORS,
440 TP_DBUS_ERROR_INVALID_INTERFACE_NAME,
441 "Invalid interface name '%s': a digit must not follow '.'",
442 name);
443 return FALSE;
444 }
445 }
446 else if (!g_ascii_isalpha (*ptr) && *ptr != '_')
447 {
448 g_set_error (error, TP_DBUS_ERRORS,
449 TP_DBUS_ERROR_INVALID_INTERFACE_NAME,
450 "Invalid interface name '%s': contains invalid character '%c'",
451 name, *ptr);
452 return FALSE;
453 }
454
455 last = *ptr;
456 }
457
458 if (last == '.')
459 {
460 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_INTERFACE_NAME,
461 "Invalid interface name '%s': must not end with '.'", name);
462 return FALSE;
463 }
464
465 if (!dot)
466 {
467 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_INTERFACE_NAME,
468 "Invalid interface name '%s': must contain '.'", name);
469 return FALSE;
470 }
471
472 return TRUE;
473 }
474
475 /**
476 * tp_dbus_check_valid_member_name:
477 * @name: a possible member name
478 * @error: used to raise %TP_DBUS_ERROR_INVALID_MEMBER_NAME if %FALSE is
479 * returned
480 *
481 * Check that the given string is a valid D-Bus member (method or signal) name.
482 *
483 * Since GIO 2.26, g_dbus_is_member_name() should always return the same
484 * thing, although the GLib function does not raise an error explaining why
485 * the interface name is incorrect.
486 *
487 * Returns: %TRUE if @name is valid
488 *
489 * Since: 0.7.1
490 */
491 gboolean
tp_dbus_check_valid_member_name(const gchar * name,GError ** error)492 tp_dbus_check_valid_member_name (const gchar *name,
493 GError **error)
494 {
495 const gchar *ptr;
496
497 g_return_val_if_fail (name != NULL, FALSE);
498
499 if (name[0] == '\0')
500 {
501 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_MEMBER_NAME,
502 "The empty string is not a valid method or signal name");
503 return FALSE;
504 }
505
506 if (strlen (name) > 255)
507 {
508 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_MEMBER_NAME,
509 "Invalid method or signal name: too long (> 255 characters)");
510 return FALSE;
511 }
512
513 for (ptr = name; *ptr != '\0'; ptr++)
514 {
515 if (g_ascii_isdigit (*ptr))
516 {
517 if (ptr == name)
518 {
519 g_set_error (error, TP_DBUS_ERRORS,
520 TP_DBUS_ERROR_INVALID_MEMBER_NAME,
521 "Invalid method or signal name '%s': must not start with "
522 "a digit", name);
523 return FALSE;
524 }
525 }
526 else if (!g_ascii_isalpha (*ptr) && *ptr != '_')
527 {
528 g_set_error (error, TP_DBUS_ERRORS,
529 TP_DBUS_ERROR_INVALID_MEMBER_NAME,
530 "Invalid method or signal name '%s': contains invalid "
531 "character '%c'",
532 name, *ptr);
533 return FALSE;
534 }
535 }
536
537 return TRUE;
538 }
539
540 /**
541 * tp_dbus_check_valid_object_path:
542 * @path: a possible object path
543 * @error: used to raise %TP_DBUS_ERROR_INVALID_OBJECT_PATH if %FALSE is
544 * returned
545 *
546 * Check that the given string is a valid D-Bus object path. Since GLib 2.24,
547 * g_variant_is_object_path() should always return the same thing as this
548 * function, although it doesn't provide an error explaining why the object
549 * path is invalid.
550 *
551 * Returns: %TRUE if @path is valid
552 *
553 * Since: 0.7.1
554 */
555 gboolean
tp_dbus_check_valid_object_path(const gchar * path,GError ** error)556 tp_dbus_check_valid_object_path (const gchar *path, GError **error)
557 {
558 const gchar *ptr;
559
560 g_return_val_if_fail (path != NULL, FALSE);
561
562 if (path[0] != '/')
563 {
564 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_OBJECT_PATH,
565 "Invalid object path '%s': must start with '/'",
566 path);
567 return FALSE;
568 }
569
570 if (path[1] == '\0')
571 return TRUE;
572
573 for (ptr = path + 1; *ptr != '\0'; ptr++)
574 {
575 if (*ptr == '/')
576 {
577 if (ptr[-1] == '/')
578 {
579 g_set_error (error, TP_DBUS_ERRORS,
580 TP_DBUS_ERROR_INVALID_OBJECT_PATH,
581 "Invalid object path '%s': contains '//'", path);
582 return FALSE;
583 }
584 }
585 else if (!g_ascii_isalnum (*ptr) && *ptr != '_')
586 {
587 g_set_error (error, TP_DBUS_ERRORS,
588 TP_DBUS_ERROR_INVALID_OBJECT_PATH,
589 "Invalid object path '%s': contains invalid character '%c'",
590 path, *ptr);
591 return FALSE;
592 }
593 }
594
595 if (ptr[-1] == '/')
596 {
597 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_OBJECT_PATH,
598 "Invalid object path '%s': is not '/' but does end with '/'",
599 path);
600 return FALSE;
601 }
602
603 return TRUE;
604 }
605
606 /**
607 * tp_g_value_slice_new_bytes: (skip)
608 * @length: number of bytes to copy
609 * @bytes: location of an array of bytes to be copied (this may be %NULL
610 * if and only if length is 0)
611 *
612 * Slice-allocate a #GValue containing a byte-array, using
613 * tp_g_value_slice_new_boxed(). This function is convenient to use when
614 * constructing hash tables from string to #GValue, for example.
615 *
616 * Returns: a #GValue of type %DBUS_TYPE_G_UCHAR_ARRAY whose value is a copy
617 * of @length bytes from @bytes, to be freed with tp_g_value_slice_free() or
618 * g_slice_free()
619 *
620 * Since: 0.7.27
621 */
622 GValue *
tp_g_value_slice_new_bytes(guint length,gconstpointer bytes)623 tp_g_value_slice_new_bytes (guint length,
624 gconstpointer bytes)
625 {
626 GArray *arr;
627
628 g_return_val_if_fail (length == 0 || bytes != NULL, NULL);
629 arr = g_array_sized_new (FALSE, FALSE, 1, length);
630
631 if (length > 0)
632 g_array_append_vals (arr, bytes, length);
633
634 return tp_g_value_slice_new_take_boxed (DBUS_TYPE_G_UCHAR_ARRAY, arr);
635 }
636
637 /**
638 * tp_g_value_slice_new_take_bytes: (skip)
639 * @bytes: a non-NULL #GArray of guchar, ownership of which will be taken by
640 * the #GValue
641 *
642 * Slice-allocate a #GValue containing @bytes, using
643 * tp_g_value_slice_new_boxed(). This function is convenient to use when
644 * constructing hash tables from string to #GValue, for example.
645 *
646 * Returns: a #GValue of type %DBUS_TYPE_G_UCHAR_ARRAY whose value is
647 * @bytes, to be freed with tp_g_value_slice_free() or
648 * g_slice_free()
649 *
650 * Since: 0.7.27
651 */
652 GValue *
tp_g_value_slice_new_take_bytes(GArray * bytes)653 tp_g_value_slice_new_take_bytes (GArray *bytes)
654 {
655 g_return_val_if_fail (bytes != NULL, NULL);
656 return tp_g_value_slice_new_take_boxed (DBUS_TYPE_G_UCHAR_ARRAY, bytes);
657 }
658
659 /**
660 * tp_g_value_slice_new_object_path: (skip)
661 * @path: a valid D-Bus object path which will be copied
662 *
663 * Slice-allocate a #GValue containing an object path, using
664 * tp_g_value_slice_new_boxed(). This function is convenient to use when
665 * constructing hash tables from string to #GValue, for example.
666 *
667 * Returns: a #GValue of type %DBUS_TYPE_G_OBJECT_PATH whose value is a copy
668 * of @path, to be freed with tp_g_value_slice_free() or g_slice_free()
669 *
670 * Since: 0.7.27
671 */
672 GValue *
tp_g_value_slice_new_object_path(const gchar * path)673 tp_g_value_slice_new_object_path (const gchar *path)
674 {
675 g_return_val_if_fail (tp_dbus_check_valid_object_path (path, NULL), NULL);
676 return tp_g_value_slice_new_boxed (DBUS_TYPE_G_OBJECT_PATH, path);
677 }
678
679 /**
680 * tp_g_value_slice_new_static_object_path: (skip)
681 * @path: a valid D-Bus object path which must remain valid forever
682 *
683 * Slice-allocate a #GValue containing an object path, using
684 * tp_g_value_slice_new_static_boxed(). This function is convenient to use when
685 * constructing hash tables from string to #GValue, for example.
686 *
687 * Returns: a #GValue of type %DBUS_TYPE_G_OBJECT_PATH whose value is @path,
688 * to be freed with tp_g_value_slice_free() or g_slice_free()
689 *
690 * Since: 0.7.27
691 */
692 GValue *
tp_g_value_slice_new_static_object_path(const gchar * path)693 tp_g_value_slice_new_static_object_path (const gchar *path)
694 {
695 g_return_val_if_fail (tp_dbus_check_valid_object_path (path, NULL), NULL);
696 return tp_g_value_slice_new_static_boxed (DBUS_TYPE_G_OBJECT_PATH, path);
697 }
698
699 /**
700 * tp_g_value_slice_new_take_object_path: (skip)
701 * @path: a valid D-Bus object path which will be freed with g_free() by the
702 * returned #GValue (the caller must own it before calling this function, but
703 * no longer owns it after this function returns)
704 *
705 * Slice-allocate a #GValue containing an object path, using
706 * tp_g_value_slice_new_take_boxed(). This function is convenient to use when
707 * constructing hash tables from string to #GValue, for example.
708 *
709 * Returns: a #GValue of type %DBUS_TYPE_G_OBJECT_PATH whose value is @path,
710 * to be freed with tp_g_value_slice_free() or g_slice_free()
711 *
712 * Since: 0.7.27
713 */
714 GValue *
tp_g_value_slice_new_take_object_path(gchar * path)715 tp_g_value_slice_new_take_object_path (gchar *path)
716 {
717 g_return_val_if_fail (tp_dbus_check_valid_object_path (path, NULL), NULL);
718 return tp_g_value_slice_new_take_boxed (DBUS_TYPE_G_OBJECT_PATH, path);
719 }
720
721 /**
722 * tp_asv_new: (skip)
723 * @first_key: the name of the first key (or NULL)
724 * @...: type and value for the first key, followed by a NULL-terminated list
725 * of (key, type, value) tuples
726 *
727 * Creates a new #GHashTable for use with a{sv} maps, containing the values
728 * passed in as parameters.
729 *
730 * The #GHashTable is synonymous with:
731 * <informalexample><programlisting>
732 * GHashTable *asv = g_hash_table_new_full (g_str_hash, g_str_equal,
733 * NULL, (GDestroyNotify) tp_g_value_slice_free);
734 * </programlisting></informalexample>
735 * Followed by manual insertion of each of the parameters.
736 *
737 * Parameters are stored in slice-allocated GValues and should be set using
738 * tp_asv_set_*() and retrieved using tp_asv_get_*().
739 *
740 * tp_g_value_slice_new() and tp_g_value_slice_dup() may also be used to insert
741 * into the map if required.
742 * <informalexample><programlisting>
743 * g_hash_table_insert (parameters, "account",
744 * tp_g_value_slice_new_string ("bob@mcbadgers.com"));
745 * </programlisting></informalexample>
746 *
747 * <example>
748 * <title>Using tp_asv_new()</title>
749 * <programlisting>
750 * GHashTable *parameters = tp_asv_new (
751 * "answer", G_TYPE_INT, 42,
752 * "question", G_TYPE_STRING, "We just don't know",
753 * NULL);</programlisting>
754 * </example>
755 *
756 * Allocated values will be automatically free'd when overwritten, removed or
757 * the hash table destroyed with g_hash_table_unref().
758 *
759 * Returns: a newly created #GHashTable for storing a{sv} maps, free with
760 * g_hash_table_unref().
761 * Since: 0.7.29
762 */
763 GHashTable *
tp_asv_new(const gchar * first_key,...)764 tp_asv_new (const gchar *first_key, ...)
765 {
766 va_list var_args;
767 char *key;
768 GType type;
769 GValue *value;
770 char *error = NULL; /* NB: not a GError! */
771
772 /* create a GHashTable */
773 GHashTable *asv = g_hash_table_new_full (g_str_hash, g_str_equal,
774 NULL, (GDestroyNotify) tp_g_value_slice_free);
775
776 va_start (var_args, first_key);
777
778 for (key = (char *) first_key; key != NULL; key = va_arg (var_args, char *))
779 {
780 type = va_arg (var_args, GType);
781
782 value = tp_g_value_slice_new (type);
783 G_VALUE_COLLECT (value, var_args, 0, &error);
784
785 if (error != NULL)
786 {
787 CRITICAL ("key %s: %s", key, error);
788 g_free (error);
789 error = NULL;
790 tp_g_value_slice_free (value);
791 continue;
792 }
793
794 g_hash_table_insert (asv, key, value);
795 }
796
797 va_end (var_args);
798
799 return asv;
800 }
801
802 /**
803 * tp_asv_get_boolean:
804 * @asv: (element-type utf8 GObject.Value): A GHashTable where the keys are
805 * strings and the values are GValues
806 * @key: The key to look up
807 * @valid: (out): Either %NULL, or a location to store %TRUE if the key actually
808 * exists and has a boolean value
809 *
810 * If a value for @key in @asv is present and boolean, return it,
811 * and set *@valid to %TRUE if @valid is not %NULL.
812 *
813 * Otherwise return %FALSE, and set *@valid to %FALSE if @valid is not %NULL.
814 *
815 * Returns: a boolean value for @key
816 * Since: 0.7.9
817 */
818 gboolean
tp_asv_get_boolean(const GHashTable * asv,const gchar * key,gboolean * valid)819 tp_asv_get_boolean (const GHashTable *asv,
820 const gchar *key,
821 gboolean *valid)
822 {
823 GValue *value;
824
825 g_return_val_if_fail (asv != NULL, FALSE);
826 g_return_val_if_fail (key != NULL, FALSE);
827
828 value = g_hash_table_lookup ((GHashTable *) asv, key);
829
830 if (value == NULL || !G_VALUE_HOLDS_BOOLEAN (value))
831 {
832 if (valid != NULL)
833 *valid = FALSE;
834
835 return FALSE;
836 }
837
838 if (valid != NULL)
839 *valid = TRUE;
840
841 return g_value_get_boolean (value);
842 }
843
844 /**
845 * tp_asv_set_boolean: (skip)
846 * @asv: a #GHashTable created with tp_asv_new()
847 * @key: string key
848 * @value: value
849 *
850 * Stores the value in the map.
851 *
852 * The value is stored as a slice-allocated GValue.
853 *
854 * See Also: tp_asv_new(), tp_asv_get_boolean(), tp_g_value_slice_new_boolean()
855 * Since: 0.7.29
856 */
857 void
tp_asv_set_boolean(GHashTable * asv,const gchar * key,gboolean value)858 tp_asv_set_boolean (GHashTable *asv,
859 const gchar *key,
860 gboolean value)
861 {
862 g_return_if_fail (asv != NULL);
863 g_return_if_fail (key != NULL);
864
865 g_hash_table_insert (asv, (char *) key, tp_g_value_slice_new_boolean (value));
866 }
867
868 /**
869 * tp_asv_get_bytes:
870 * @asv: (element-type utf8 GObject.Value): A GHashTable where the keys are
871 * strings and the values are GValues
872 * @key: The key to look up
873 *
874 * If a value for @key in @asv is present and is an array of bytes
875 * (its GType is %DBUS_TYPE_G_UCHAR_ARRAY), return it.
876 *
877 * Otherwise return %NULL.
878 *
879 * The returned value is not copied, and is only valid as long as the value
880 * for @key in @asv is not removed or altered. Copy it with
881 * g_boxed_copy (DBUS_TYPE_G_UCHAR_ARRAY, ...) if you need to keep
882 * it for longer.
883 *
884 * Returns: (transfer none) (allow-none) (element-type guint8): the string value
885 * of @key, or %NULL
886 * Since: 0.7.9
887 */
888 const GArray *
tp_asv_get_bytes(const GHashTable * asv,const gchar * key)889 tp_asv_get_bytes (const GHashTable *asv,
890 const gchar *key)
891 {
892 GValue *value;
893
894 g_return_val_if_fail (asv != NULL, NULL);
895 g_return_val_if_fail (key != NULL, NULL);
896
897 value = g_hash_table_lookup ((GHashTable *) asv, key);
898
899 if (value == NULL || !G_VALUE_HOLDS (value, DBUS_TYPE_G_UCHAR_ARRAY))
900 return NULL;
901
902 return g_value_get_boxed (value);
903 }
904
905 /**
906 * tp_asv_set_bytes: (skip)
907 * @asv: a #GHashTable created with tp_asv_new()
908 * @key: string key
909 * @length: the number of bytes to copy
910 * @bytes: location of an array of bytes to be copied (this may be %NULL
911 * if and only if length is 0)
912 *
913 * Stores the value in the map.
914 *
915 * The value is stored as a slice-allocated GValue.
916 *
917 * See Also: tp_asv_new(), tp_asv_get_bytes(), tp_g_value_slice_new_bytes()
918 * Since: 0.7.29
919 */
920 void
tp_asv_set_bytes(GHashTable * asv,const gchar * key,guint length,gconstpointer bytes)921 tp_asv_set_bytes (GHashTable *asv,
922 const gchar *key,
923 guint length,
924 gconstpointer bytes)
925 {
926 g_return_if_fail (asv != NULL);
927 g_return_if_fail (key != NULL);
928 g_return_if_fail (!(length > 0 && bytes == NULL));
929
930 g_hash_table_insert (asv, (char *) key,
931 tp_g_value_slice_new_bytes (length, bytes));
932 }
933
934 /**
935 * tp_asv_take_bytes: (skip)
936 * @asv: a #GHashTable created with tp_asv_new()
937 * @key: string key
938 * @value: a non-NULL #GArray of %guchar, ownership of which will be taken by
939 * the #GValue
940 *
941 * Stores the value in the map.
942 *
943 * The value is stored as a slice-allocated GValue.
944 *
945 * See Also: tp_asv_new(), tp_asv_get_bytes(), tp_g_value_slice_new_take_bytes()
946 * Since: 0.7.29
947 */
948 void
tp_asv_take_bytes(GHashTable * asv,const gchar * key,GArray * value)949 tp_asv_take_bytes (GHashTable *asv,
950 const gchar *key,
951 GArray *value)
952 {
953 g_return_if_fail (asv != NULL);
954 g_return_if_fail (key != NULL);
955 g_return_if_fail (value != NULL);
956
957 g_hash_table_insert (asv, (char *) key,
958 tp_g_value_slice_new_take_bytes (value));
959 }
960
961 /**
962 * tp_asv_get_string:
963 * @asv: (element-type utf8 GObject.Value): A GHashTable where the keys are
964 * strings and the values are GValues
965 * @key: The key to look up
966 *
967 * If a value for @key in @asv is present and is a string, return it.
968 *
969 * Otherwise return %NULL.
970 *
971 * The returned value is not copied, and is only valid as long as the value
972 * for @key in @asv is not removed or altered. Copy it with g_strdup() if you
973 * need to keep it for longer.
974 *
975 * Returns: (transfer none) (allow-none): the string value of @key, or %NULL
976 * Since: 0.7.9
977 */
978 const gchar *
tp_asv_get_string(const GHashTable * asv,const gchar * key)979 tp_asv_get_string (const GHashTable *asv,
980 const gchar *key)
981 {
982 GValue *value;
983
984 g_return_val_if_fail (asv != NULL, NULL);
985 g_return_val_if_fail (key != NULL, NULL);
986
987 value = g_hash_table_lookup ((GHashTable *) asv, key);
988
989 if (value == NULL || !G_VALUE_HOLDS_STRING (value))
990 return NULL;
991
992 return g_value_get_string (value);
993 }
994
995 /**
996 * tp_asv_set_string: (skip)
997 * @asv: a #GHashTable created with tp_asv_new()
998 * @key: string key
999 * @value: value
1000 *
1001 * Stores the value in the map.
1002 *
1003 * The value is stored as a slice-allocated GValue.
1004 *
1005 * See Also: tp_asv_new(), tp_asv_get_string(), tp_g_value_slice_new_string()
1006 * Since: 0.7.29
1007 */
1008 void
tp_asv_set_string(GHashTable * asv,const gchar * key,const gchar * value)1009 tp_asv_set_string (GHashTable *asv,
1010 const gchar *key,
1011 const gchar *value)
1012 {
1013 g_return_if_fail (asv != NULL);
1014 g_return_if_fail (key != NULL);
1015
1016 g_hash_table_insert (asv, (char *) key, tp_g_value_slice_new_string (value));
1017 }
1018
1019 /**
1020 * tp_asv_take_string: (skip)
1021 * @asv: a #GHashTable created with tp_asv_new()
1022 * @key: string key
1023 * @value: value
1024 *
1025 * Stores the value in the map.
1026 *
1027 * The value is stored as a slice-allocated GValue.
1028 *
1029 * See Also: tp_asv_new(), tp_asv_get_string(),
1030 * tp_g_value_slice_new_take_string()
1031 * Since: 0.7.29
1032 */
1033 void
tp_asv_take_string(GHashTable * asv,const gchar * key,gchar * value)1034 tp_asv_take_string (GHashTable *asv,
1035 const gchar *key,
1036 gchar *value)
1037 {
1038 g_return_if_fail (asv != NULL);
1039 g_return_if_fail (key != NULL);
1040
1041 g_hash_table_insert (asv, (char *) key,
1042 tp_g_value_slice_new_take_string (value));
1043 }
1044
1045 /**
1046 * tp_asv_set_static_string: (skip)
1047 * @asv: a #GHashTable created with tp_asv_new()
1048 * @key: string key
1049 * @value: value
1050 *
1051 * Stores the value in the map.
1052 *
1053 * The value is stored as a slice-allocated GValue.
1054 *
1055 * See Also: tp_asv_new(), tp_asv_get_string(),
1056 * tp_g_value_slice_new_static_string()
1057 * Since: 0.7.29
1058 */
1059 void
tp_asv_set_static_string(GHashTable * asv,const gchar * key,const gchar * value)1060 tp_asv_set_static_string (GHashTable *asv,
1061 const gchar *key,
1062 const gchar *value)
1063 {
1064 g_return_if_fail (asv != NULL);
1065 g_return_if_fail (key != NULL);
1066
1067 g_hash_table_insert (asv, (char *) key,
1068 tp_g_value_slice_new_static_string (value));
1069 }
1070
1071 /**
1072 * tp_asv_get_int32:
1073 * @asv: (element-type utf8 GObject.Value): A GHashTable where the keys are
1074 * strings and the values are GValues
1075 * @key: The key to look up
1076 * @valid: (out): Either %NULL, or a location in which to store %TRUE on success
1077 * or %FALSE on failure
1078 *
1079 * If a value for @key in @asv is present, has an integer type used by
1080 * dbus-glib (guchar, gint, guint, gint64 or guint64) and fits in the
1081 * range of a gint32, return it, and if @valid is not %NULL, set *@valid to
1082 * %TRUE.
1083 *
1084 * Otherwise, return 0, and if @valid is not %NULL, set *@valid to %FALSE.
1085 *
1086 * Returns: the 32-bit signed integer value of @key, or 0
1087 * Since: 0.7.9
1088 */
1089 gint32
tp_asv_get_int32(const GHashTable * asv,const gchar * key,gboolean * valid)1090 tp_asv_get_int32 (const GHashTable *asv,
1091 const gchar *key,
1092 gboolean *valid)
1093 {
1094 gint64 i;
1095 guint64 u;
1096 gint32 ret;
1097 GValue *value;
1098
1099 g_return_val_if_fail (asv != NULL, 0);
1100 g_return_val_if_fail (key != NULL, 0);
1101
1102 value = g_hash_table_lookup ((GHashTable *) asv, key);
1103
1104 if (value == NULL)
1105 goto return_invalid;
1106
1107 switch (G_VALUE_TYPE (value))
1108 {
1109 case G_TYPE_UCHAR:
1110 ret = g_value_get_uchar (value);
1111 break;
1112
1113 case G_TYPE_UINT:
1114 u = g_value_get_uint (value);
1115
1116 if (G_UNLIKELY (u > G_MAXINT32))
1117 goto return_invalid;
1118
1119 ret = u;
1120 break;
1121
1122 case G_TYPE_INT:
1123 ret = g_value_get_int (value);
1124 break;
1125
1126 case G_TYPE_INT64:
1127 i = g_value_get_int64 (value);
1128
1129 if (G_UNLIKELY (i < G_MININT32 || i > G_MAXINT32))
1130 goto return_invalid;
1131
1132 ret = i;
1133 break;
1134
1135 case G_TYPE_UINT64:
1136 u = g_value_get_uint64 (value);
1137
1138 if (G_UNLIKELY (u > G_MAXINT32))
1139 goto return_invalid;
1140
1141 ret = u;
1142 break;
1143
1144 default:
1145 goto return_invalid;
1146 }
1147
1148 if (valid != NULL)
1149 *valid = TRUE;
1150
1151 return ret;
1152
1153 return_invalid:
1154 if (valid != NULL)
1155 *valid = FALSE;
1156
1157 return 0;
1158 }
1159
1160 /**
1161 * tp_asv_set_int32: (skip)
1162 * @asv: a #GHashTable created with tp_asv_new()
1163 * @key: string key
1164 * @value: value
1165 *
1166 * Stores the value in the map.
1167 *
1168 * The value is stored as a slice-allocated GValue.
1169 *
1170 * See Also: tp_asv_new(), tp_asv_get_int32(), tp_g_value_slice_new_int()
1171 * Since: 0.7.29
1172 */
1173 void
tp_asv_set_int32(GHashTable * asv,const gchar * key,gint32 value)1174 tp_asv_set_int32 (GHashTable *asv,
1175 const gchar *key,
1176 gint32 value)
1177 {
1178 g_return_if_fail (asv != NULL);
1179 g_return_if_fail (key != NULL);
1180
1181 g_hash_table_insert (asv, (char *) key, tp_g_value_slice_new_int (value));
1182 }
1183
1184 /**
1185 * tp_asv_get_uint32:
1186 * @asv: (element-type utf8 GObject.Value): A GHashTable where the keys are
1187 * strings and the values are GValues
1188 * @key: The key to look up
1189 * @valid: (out): Either %NULL, or a location in which to store %TRUE on success
1190 * or %FALSE on failure
1191 *
1192 * If a value for @key in @asv is present, has an integer type used by
1193 * dbus-glib (guchar, gint, guint, gint64 or guint64) and fits in the
1194 * range of a guint32, return it, and if @valid is not %NULL, set *@valid to
1195 * %TRUE.
1196 *
1197 * Otherwise, return 0, and if @valid is not %NULL, set *@valid to %FALSE.
1198 *
1199 * Returns: the 32-bit unsigned integer value of @key, or 0
1200 * Since: 0.7.9
1201 */
1202 guint32
tp_asv_get_uint32(const GHashTable * asv,const gchar * key,gboolean * valid)1203 tp_asv_get_uint32 (const GHashTable *asv,
1204 const gchar *key,
1205 gboolean *valid)
1206 {
1207 gint64 i;
1208 guint64 u;
1209 guint32 ret;
1210 GValue *value;
1211
1212 g_return_val_if_fail (asv != NULL, 0);
1213 g_return_val_if_fail (key != NULL, 0);
1214
1215 value = g_hash_table_lookup ((GHashTable *) asv, key);
1216
1217 if (value == NULL)
1218 goto return_invalid;
1219
1220 switch (G_VALUE_TYPE (value))
1221 {
1222 case G_TYPE_UCHAR:
1223 ret = g_value_get_uchar (value);
1224 break;
1225
1226 case G_TYPE_UINT:
1227 ret = g_value_get_uint (value);
1228 break;
1229
1230 case G_TYPE_INT:
1231 i = g_value_get_int (value);
1232
1233 if (G_UNLIKELY (i < 0))
1234 goto return_invalid;
1235
1236 ret = i;
1237 break;
1238
1239 case G_TYPE_INT64:
1240 i = g_value_get_int64 (value);
1241
1242 if (G_UNLIKELY (i < 0 || i > G_MAXUINT32))
1243 goto return_invalid;
1244
1245 ret = i;
1246 break;
1247
1248 case G_TYPE_UINT64:
1249 u = g_value_get_uint64 (value);
1250
1251 if (G_UNLIKELY (u > G_MAXUINT32))
1252 goto return_invalid;
1253
1254 ret = u;
1255 break;
1256
1257 default:
1258 goto return_invalid;
1259 }
1260
1261 if (valid != NULL)
1262 *valid = TRUE;
1263
1264 return ret;
1265
1266 return_invalid:
1267 if (valid != NULL)
1268 *valid = FALSE;
1269
1270 return 0;
1271 }
1272
1273 /**
1274 * tp_asv_set_uint32: (skip)
1275 * @asv: a #GHashTable created with tp_asv_new()
1276 * @key: string key
1277 * @value: value
1278 *
1279 * Stores the value in the map.
1280 *
1281 * The value is stored as a slice-allocated GValue.
1282 *
1283 * See Also: tp_asv_new(), tp_asv_get_uint32(), tp_g_value_slice_new_uint()
1284 * Since: 0.7.29
1285 */
1286 void
tp_asv_set_uint32(GHashTable * asv,const gchar * key,guint32 value)1287 tp_asv_set_uint32 (GHashTable *asv,
1288 const gchar *key,
1289 guint32 value)
1290 {
1291 g_return_if_fail (asv != NULL);
1292 g_return_if_fail (key != NULL);
1293
1294 g_hash_table_insert (asv, (char *) key, tp_g_value_slice_new_uint (value));
1295 }
1296
1297 /**
1298 * tp_asv_get_int64:
1299 * @asv: (element-type utf8 GObject.Value): A GHashTable where the keys are
1300 * strings and the values are GValues
1301 * @key: The key to look up
1302 * @valid: (out): Either %NULL, or a location in which to store %TRUE on success
1303 * or %FALSE on failure
1304 *
1305 * If a value for @key in @asv is present, has an integer type used by
1306 * dbus-glib (guchar, gint, guint, gint64 or guint64) and fits in the
1307 * range of a gint64, return it, and if @valid is not %NULL, set *@valid to
1308 * %TRUE.
1309 *
1310 * Otherwise, return 0, and if @valid is not %NULL, set *@valid to %FALSE.
1311 *
1312 * Returns: the 64-bit signed integer value of @key, or 0
1313 * Since: 0.7.9
1314 */
1315 gint64
tp_asv_get_int64(const GHashTable * asv,const gchar * key,gboolean * valid)1316 tp_asv_get_int64 (const GHashTable *asv,
1317 const gchar *key,
1318 gboolean *valid)
1319 {
1320 gint64 ret;
1321 guint64 u;
1322 GValue *value;
1323
1324 g_return_val_if_fail (asv != NULL, 0);
1325 g_return_val_if_fail (key != NULL, 0);
1326
1327 value = g_hash_table_lookup ((GHashTable *) asv, key);
1328
1329 if (value == NULL)
1330 goto return_invalid;
1331
1332 switch (G_VALUE_TYPE (value))
1333 {
1334 case G_TYPE_UCHAR:
1335 ret = g_value_get_uchar (value);
1336 break;
1337
1338 case G_TYPE_UINT:
1339 ret = g_value_get_uint (value);
1340 break;
1341
1342 case G_TYPE_INT:
1343 ret = g_value_get_int (value);
1344 break;
1345
1346 case G_TYPE_INT64:
1347 ret = g_value_get_int64 (value);
1348 break;
1349
1350 case G_TYPE_UINT64:
1351 u = g_value_get_uint64 (value);
1352
1353 if (G_UNLIKELY (u > G_MAXINT64))
1354 goto return_invalid;
1355
1356 ret = u;
1357 break;
1358
1359 default:
1360 goto return_invalid;
1361 }
1362
1363 if (valid != NULL)
1364 *valid = TRUE;
1365
1366 return ret;
1367
1368 return_invalid:
1369 if (valid != NULL)
1370 *valid = FALSE;
1371
1372 return 0;
1373 }
1374
1375 /**
1376 * tp_asv_set_int64: (skip)
1377 * @asv: a #GHashTable created with tp_asv_new()
1378 * @key: string key
1379 * @value: value
1380 *
1381 * Stores the value in the map.
1382 *
1383 * The value is stored as a slice-allocated GValue.
1384 *
1385 * See Also: tp_asv_new(), tp_asv_get_int64(), tp_g_value_slice_new_int64()
1386 * Since: 0.7.29
1387 */
1388 void
tp_asv_set_int64(GHashTable * asv,const gchar * key,gint64 value)1389 tp_asv_set_int64 (GHashTable *asv,
1390 const gchar *key,
1391 gint64 value)
1392 {
1393 g_return_if_fail (asv != NULL);
1394 g_return_if_fail (key != NULL);
1395
1396 g_hash_table_insert (asv, (char *) key, tp_g_value_slice_new_int64 (value));
1397 }
1398
1399 /**
1400 * tp_asv_get_uint64:
1401 * @asv: (element-type utf8 GObject.Value): A GHashTable where the keys are
1402 * strings and the values are GValues
1403 * @key: The key to look up
1404 * @valid: (out): Either %NULL, or a location in which to store %TRUE on success
1405 * or %FALSE on failure
1406 *
1407 * If a value for @key in @asv is present, has an integer type used by
1408 * dbus-glib (guchar, gint, guint, gint64 or guint64) and is non-negative,
1409 * return it, and if @valid is not %NULL, set *@valid to %TRUE.
1410 *
1411 * Otherwise, return 0, and if @valid is not %NULL, set *@valid to %FALSE.
1412 *
1413 * Returns: the 64-bit unsigned integer value of @key, or 0
1414 * Since: 0.7.9
1415 */
1416 guint64
tp_asv_get_uint64(const GHashTable * asv,const gchar * key,gboolean * valid)1417 tp_asv_get_uint64 (const GHashTable *asv,
1418 const gchar *key,
1419 gboolean *valid)
1420 {
1421 gint64 tmp;
1422 guint64 ret;
1423 GValue *value;
1424
1425 g_return_val_if_fail (asv != NULL, 0);
1426 g_return_val_if_fail (key != NULL, 0);
1427
1428 value = g_hash_table_lookup ((GHashTable *) asv, key);
1429
1430 if (value == NULL)
1431 goto return_invalid;
1432
1433 switch (G_VALUE_TYPE (value))
1434 {
1435 case G_TYPE_UCHAR:
1436 ret = g_value_get_uchar (value);
1437 break;
1438
1439 case G_TYPE_UINT:
1440 ret = g_value_get_uint (value);
1441 break;
1442
1443 case G_TYPE_INT:
1444 tmp = g_value_get_int (value);
1445
1446 if (G_UNLIKELY (tmp < 0))
1447 goto return_invalid;
1448
1449 ret = tmp;
1450 break;
1451
1452 case G_TYPE_INT64:
1453 tmp = g_value_get_int64 (value);
1454
1455 if (G_UNLIKELY (tmp < 0))
1456 goto return_invalid;
1457
1458 ret = tmp;
1459 break;
1460
1461 case G_TYPE_UINT64:
1462 ret = g_value_get_uint64 (value);
1463 break;
1464
1465 default:
1466 goto return_invalid;
1467 }
1468
1469 if (valid != NULL)
1470 *valid = TRUE;
1471
1472 return ret;
1473
1474 return_invalid:
1475 if (valid != NULL)
1476 *valid = FALSE;
1477
1478 return 0;
1479 }
1480
1481 /**
1482 * tp_asv_set_uint64: (skip)
1483 * @asv: a #GHashTable created with tp_asv_new()
1484 * @key: string key
1485 * @value: value
1486 *
1487 * Stores the value in the map.
1488 *
1489 * The value is stored as a slice-allocated GValue.
1490 *
1491 * See Also: tp_asv_new(), tp_asv_get_uint64(), tp_g_value_slice_new_uint64()
1492 * Since: 0.7.29
1493 */
1494 void
tp_asv_set_uint64(GHashTable * asv,const gchar * key,guint64 value)1495 tp_asv_set_uint64 (GHashTable *asv,
1496 const gchar *key,
1497 guint64 value)
1498 {
1499 g_return_if_fail (asv != NULL);
1500 g_return_if_fail (key != NULL);
1501
1502 g_hash_table_insert (asv, (char *) key, tp_g_value_slice_new_uint64 (value));
1503 }
1504
1505 /**
1506 * tp_asv_get_double:
1507 * @asv: (element-type utf8 GObject.Value): A GHashTable where the keys are
1508 * strings and the values are GValues
1509 * @key: The key to look up
1510 * @valid: (out): Either %NULL, or a location in which to store %TRUE on success
1511 * or %FALSE on failure
1512 *
1513 * If a value for @key in @asv is present and has any numeric type used by
1514 * dbus-glib (guchar, gint, guint, gint64, guint64 or gdouble),
1515 * return it as a double, and if @valid is not %NULL, set *@valid to %TRUE.
1516 *
1517 * Otherwise, return 0.0, and if @valid is not %NULL, set *@valid to %FALSE.
1518 *
1519 * Returns: the double precision floating-point value of @key, or 0.0
1520 * Since: 0.7.9
1521 */
1522 gdouble
tp_asv_get_double(const GHashTable * asv,const gchar * key,gboolean * valid)1523 tp_asv_get_double (const GHashTable *asv,
1524 const gchar *key,
1525 gboolean *valid)
1526 {
1527 gdouble ret;
1528 GValue *value;
1529
1530 g_return_val_if_fail (asv != NULL, 0.0);
1531 g_return_val_if_fail (key != NULL, 0.0);
1532
1533 value = g_hash_table_lookup ((GHashTable *) asv, key);
1534
1535 if (value == NULL)
1536 goto return_invalid;
1537
1538 switch (G_VALUE_TYPE (value))
1539 {
1540 case G_TYPE_DOUBLE:
1541 ret = g_value_get_double (value);
1542 break;
1543
1544 case G_TYPE_UCHAR:
1545 ret = g_value_get_uchar (value);
1546 break;
1547
1548 case G_TYPE_UINT:
1549 ret = g_value_get_uint (value);
1550 break;
1551
1552 case G_TYPE_INT:
1553 ret = g_value_get_int (value);
1554 break;
1555
1556 case G_TYPE_INT64:
1557 ret = g_value_get_int64 (value);
1558 break;
1559
1560 case G_TYPE_UINT64:
1561 ret = g_value_get_uint64 (value);
1562 break;
1563
1564 default:
1565 goto return_invalid;
1566 }
1567
1568 if (valid != NULL)
1569 *valid = TRUE;
1570
1571 return ret;
1572
1573 return_invalid:
1574 if (valid != NULL)
1575 *valid = FALSE;
1576
1577 return 0;
1578 }
1579
1580 /**
1581 * tp_asv_set_double: (skip)
1582 * @asv: a #GHashTable created with tp_asv_new()
1583 * @key: string key
1584 * @value: value
1585 *
1586 * Stores the value in the map.
1587 *
1588 * The value is stored as a slice-allocated GValue.
1589 *
1590 * See Also: tp_asv_new(), tp_asv_get_double(), tp_g_value_slice_new_double()
1591 * Since: 0.7.29
1592 */
1593 void
tp_asv_set_double(GHashTable * asv,const gchar * key,gdouble value)1594 tp_asv_set_double (GHashTable *asv,
1595 const gchar *key,
1596 gdouble value)
1597 {
1598 g_return_if_fail (asv != NULL);
1599 g_return_if_fail (key != NULL);
1600
1601 g_hash_table_insert (asv, (char *) key, tp_g_value_slice_new_double (value));
1602 }
1603
1604 /**
1605 * tp_asv_get_object_path:
1606 * @asv: (element-type utf8 GObject.Value): A GHashTable where the keys are
1607 * strings and the values are GValues
1608 * @key: The key to look up
1609 *
1610 * If a value for @key in @asv is present and is an object path, return it.
1611 *
1612 * Otherwise return %NULL.
1613 *
1614 * The returned value is not copied, and is only valid as long as the value
1615 * for @key in @asv is not removed or altered. Copy it with g_strdup() if you
1616 * need to keep it for longer.
1617 *
1618 * Returns: (transfer none) (allow-none): the object-path value of @key, or
1619 * %NULL
1620 * Since: 0.7.9
1621 */
1622 const gchar *
tp_asv_get_object_path(const GHashTable * asv,const gchar * key)1623 tp_asv_get_object_path (const GHashTable *asv,
1624 const gchar *key)
1625 {
1626 GValue *value;
1627
1628 g_return_val_if_fail (asv != NULL, 0);
1629 g_return_val_if_fail (key != NULL, 0);
1630
1631 value = g_hash_table_lookup ((GHashTable *) asv, key);
1632
1633 if (value == NULL || !G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH))
1634 return NULL;
1635
1636 return g_value_get_boxed (value);
1637 }
1638
1639 /**
1640 * tp_asv_set_object_path: (skip)
1641 * @asv: a #GHashTable created with tp_asv_new()
1642 * @key: string key
1643 * @value: value
1644 *
1645 * Stores the value in the map.
1646 *
1647 * The value is stored as a slice-allocated GValue.
1648 *
1649 * See Also: tp_asv_new(), tp_asv_get_object_path(),
1650 * tp_g_value_slice_new_object_path()
1651 * Since: 0.7.29
1652 */
1653 void
tp_asv_set_object_path(GHashTable * asv,const gchar * key,const gchar * value)1654 tp_asv_set_object_path (GHashTable *asv,
1655 const gchar *key,
1656 const gchar *value)
1657 {
1658 g_return_if_fail (asv != NULL);
1659 g_return_if_fail (key != NULL);
1660
1661 g_hash_table_insert (asv, (char *) key,
1662 tp_g_value_slice_new_object_path (value));
1663 }
1664
1665 /**
1666 * tp_asv_take_object_path: (skip)
1667 * @asv: a #GHashTable created with tp_asv_new()
1668 * @key: string key
1669 * @value: value
1670 *
1671 * Stores the value in the map.
1672 *
1673 * The value is stored as a slice-allocated GValue.
1674 *
1675 * See Also: tp_asv_new(), tp_asv_get_object_path(),
1676 * tp_g_value_slice_new_take_object_path()
1677 * Since: 0.7.29
1678 */
1679 void
tp_asv_take_object_path(GHashTable * asv,const gchar * key,gchar * value)1680 tp_asv_take_object_path (GHashTable *asv,
1681 const gchar *key,
1682 gchar *value)
1683 {
1684 g_return_if_fail (asv != NULL);
1685 g_return_if_fail (key != NULL);
1686
1687 g_hash_table_insert (asv, (char *) key,
1688 tp_g_value_slice_new_take_object_path (value));
1689 }
1690
1691 /**
1692 * tp_asv_set_static_object_path: (skip)
1693 * @asv: a #GHashTable created with tp_asv_new()
1694 * @key: string key
1695 * @value: value
1696 *
1697 * Stores the value in the map.
1698 *
1699 * The value is stored as a slice-allocated GValue.
1700 *
1701 * See Also: tp_asv_new(), tp_asv_get_object_path(),
1702 * tp_g_value_slice_new_static_object_path()
1703 * Since: 0.7.29
1704 */
1705 void
tp_asv_set_static_object_path(GHashTable * asv,const gchar * key,const gchar * value)1706 tp_asv_set_static_object_path (GHashTable *asv,
1707 const gchar *key,
1708 const gchar *value)
1709 {
1710 g_return_if_fail (asv != NULL);
1711 g_return_if_fail (key != NULL);
1712
1713 g_hash_table_insert (asv, (char *) key,
1714 tp_g_value_slice_new_static_object_path (value));
1715 }
1716
1717 /**
1718 * tp_asv_get_boxed:
1719 * @asv: (element-type utf8 GObject.Value): A GHashTable where the keys are
1720 * strings and the values are GValues
1721 * @key: The key to look up
1722 * @type: The type that the key's value should have, which must be derived
1723 * from %G_TYPE_BOXED
1724 *
1725 * If a value for @key in @asv is present and is of the desired type,
1726 * return it.
1727 *
1728 * Otherwise return %NULL.
1729 *
1730 * The returned value is not copied, and is only valid as long as the value
1731 * for @key in @asv is not removed or altered. Copy it, for instance with
1732 * g_boxed_copy(), if you need to keep it for longer.
1733 *
1734 * Returns: (transfer none) (allow-none): the value of @key, or %NULL
1735 * Since: 0.7.9
1736 */
1737 gpointer
tp_asv_get_boxed(const GHashTable * asv,const gchar * key,GType type)1738 tp_asv_get_boxed (const GHashTable *asv,
1739 const gchar *key,
1740 GType type)
1741 {
1742 GValue *value;
1743
1744 g_return_val_if_fail (asv != NULL, NULL);
1745 g_return_val_if_fail (key != NULL, NULL);
1746 g_return_val_if_fail (G_TYPE_FUNDAMENTAL (type) == G_TYPE_BOXED, NULL);
1747
1748 value = g_hash_table_lookup ((GHashTable *) asv, key);
1749
1750 if (value == NULL || !G_VALUE_HOLDS (value, type))
1751 return NULL;
1752
1753 return g_value_get_boxed (value);
1754 }
1755
1756 /**
1757 * tp_asv_set_boxed: (skip)
1758 * @asv: a #GHashTable created with tp_asv_new()
1759 * @key: string key
1760 * @type: the type of the key's value, which must be derived from %G_TYPE_BOXED
1761 * @value: value
1762 *
1763 * Stores the value in the map.
1764 *
1765 * The value is stored as a slice-allocated GValue.
1766 *
1767 * See Also: tp_asv_new(), tp_asv_get_boxed(), tp_g_value_slice_new_boxed()
1768 * Since: 0.7.29
1769 */
1770 void
tp_asv_set_boxed(GHashTable * asv,const gchar * key,GType type,gconstpointer value)1771 tp_asv_set_boxed (GHashTable *asv,
1772 const gchar *key,
1773 GType type,
1774 gconstpointer value)
1775 {
1776 g_return_if_fail (asv != NULL);
1777 g_return_if_fail (key != NULL);
1778 g_return_if_fail (G_TYPE_FUNDAMENTAL (type) == G_TYPE_BOXED);
1779
1780 g_hash_table_insert (asv, (char *) key,
1781 tp_g_value_slice_new_boxed (type, value));
1782 }
1783
1784 /**
1785 * tp_asv_take_boxed: (skip)
1786 * @asv: a #GHashTable created with tp_asv_new()
1787 * @key: string key
1788 * @type: the type of the key's value, which must be derived from %G_TYPE_BOXED
1789 * @value: value
1790 *
1791 * Stores the value in the map.
1792 *
1793 * The value is stored as a slice-allocated GValue.
1794 *
1795 * See Also: tp_asv_new(), tp_asv_get_boxed(), tp_g_value_slice_new_take_boxed()
1796 * Since: 0.7.29
1797 */
1798 void
tp_asv_take_boxed(GHashTable * asv,const gchar * key,GType type,gpointer value)1799 tp_asv_take_boxed (GHashTable *asv,
1800 const gchar *key,
1801 GType type,
1802 gpointer value)
1803 {
1804 g_return_if_fail (asv != NULL);
1805 g_return_if_fail (key != NULL);
1806 g_return_if_fail (G_TYPE_FUNDAMENTAL (type) == G_TYPE_BOXED);
1807
1808 g_hash_table_insert (asv, (char *) key,
1809 tp_g_value_slice_new_take_boxed (type, value));
1810 }
1811
1812 /**
1813 * tp_asv_set_static_boxed: (skip)
1814 * @asv: a #GHashTable created with tp_asv_new()
1815 * @key: string key
1816 * @type: the type of the key's value, which must be derived from %G_TYPE_BOXED
1817 * @value: value
1818 *
1819 * Stores the value in the map.
1820 *
1821 * The value is stored as a slice-allocated GValue.
1822 *
1823 * See Also: tp_asv_new(), tp_asv_get_boxed(),
1824 * tp_g_value_slice_new_static_boxed()
1825 * Since: 0.7.29
1826 */
1827 void
tp_asv_set_static_boxed(GHashTable * asv,const gchar * key,GType type,gconstpointer value)1828 tp_asv_set_static_boxed (GHashTable *asv,
1829 const gchar *key,
1830 GType type,
1831 gconstpointer value)
1832 {
1833 g_return_if_fail (asv != NULL);
1834 g_return_if_fail (key != NULL);
1835 g_return_if_fail (G_TYPE_FUNDAMENTAL (type) == G_TYPE_BOXED);
1836
1837 g_hash_table_insert (asv, (char *) key,
1838 tp_g_value_slice_new_static_boxed (type, value));
1839 }
1840
1841 /**
1842 * tp_asv_get_strv:
1843 * @asv: (element-type utf8 GObject.Value): A GHashTable where the keys are
1844 * strings and the values are GValues
1845 * @key: The key to look up
1846 *
1847 * If a value for @key in @asv is present and is an array of strings (strv),
1848 * return it.
1849 *
1850 * Otherwise return %NULL.
1851 *
1852 * The returned value is not copied, and is only valid as long as the value
1853 * for @key in @asv is not removed or altered. Copy it with g_strdupv() if you
1854 * need to keep it for longer.
1855 *
1856 * Returns: (transfer none) (allow-none): the %NULL-terminated string-array
1857 * value of @key, or %NULL
1858 * Since: 0.7.9
1859 */
1860 const gchar * const *
tp_asv_get_strv(const GHashTable * asv,const gchar * key)1861 tp_asv_get_strv (const GHashTable *asv,
1862 const gchar *key)
1863 {
1864 GValue *value;
1865
1866 g_return_val_if_fail (asv != NULL, NULL);
1867 g_return_val_if_fail (key != NULL, NULL);
1868
1869 value = g_hash_table_lookup ((GHashTable *) asv, key);
1870
1871 if (value == NULL || !G_VALUE_HOLDS (value, G_TYPE_STRV))
1872 return NULL;
1873
1874 return g_value_get_boxed (value);
1875 }
1876
1877 /**
1878 * tp_asv_set_strv: (skip)
1879 * @asv: a #GHashTable created with tp_asv_new()
1880 * @key: string key
1881 * @value: a %NULL-terminated string array
1882 *
1883 * Stores the value in the map.
1884 *
1885 * The value is stored as a slice-allocated GValue.
1886 *
1887 * See Also: tp_asv_new(), tp_asv_get_strv()
1888 * Since: 0.7.29
1889 */
1890 void
tp_asv_set_strv(GHashTable * asv,const gchar * key,gchar ** value)1891 tp_asv_set_strv (GHashTable *asv,
1892 const gchar *key,
1893 gchar **value)
1894 {
1895 g_return_if_fail (asv != NULL);
1896 g_return_if_fail (key != NULL);
1897
1898 g_hash_table_insert (asv, (char *) key,
1899 tp_g_value_slice_new_boxed (G_TYPE_STRV, value));
1900 }
1901
1902 /**
1903 * tp_asv_lookup: (skip)
1904 * @asv: A GHashTable where the keys are strings and the values are GValues
1905 * @key: The key to look up
1906 *
1907 * If a value for @key in @asv is present, return it. Otherwise return %NULL.
1908 *
1909 * The returned value is not copied, and is only valid as long as the value
1910 * for @key in @asv is not removed or altered. Copy it with (for instance)
1911 * g_value_copy() if you need to keep it for longer.
1912 *
1913 * Returns: the value of @key, or %NULL
1914 * Since: 0.7.9
1915 */
1916 const GValue *
tp_asv_lookup(const GHashTable * asv,const gchar * key)1917 tp_asv_lookup (const GHashTable *asv,
1918 const gchar *key)
1919 {
1920 g_return_val_if_fail (asv != NULL, NULL);
1921 g_return_val_if_fail (key != NULL, NULL);
1922
1923 return g_hash_table_lookup ((GHashTable *) asv, key);
1924 }
1925
1926 /**
1927 * tp_asv_dump: (skip)
1928 * @asv: a #GHashTable created with tp_asv_new()
1929 *
1930 * Dumps the a{sv} map to the debugging console.
1931 *
1932 * The purpose of this function is give the programmer the ability to easily
1933 * inspect the contents of an a{sv} map for debugging purposes.
1934 */
1935 void
tp_asv_dump(GHashTable * asv)1936 tp_asv_dump (GHashTable *asv)
1937 {
1938 GHashTableIter iter;
1939 char *key;
1940 GValue *value;
1941
1942 g_return_if_fail (asv != NULL);
1943
1944 g_debug ("{");
1945
1946 g_hash_table_iter_init (&iter, asv);
1947 while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value))
1948 {
1949 char *str = g_strdup_value_contents (value);
1950 g_debug (" '%s' : %s", key, str);
1951 g_free (str);
1952 }
1953
1954 g_debug ("}");
1955 }
1956