xref: /illumos-gate/usr/src/lib/hal/libhal/common/libhal.c (revision 9f6ee244)
1 /***************************************************************************
2  * CVSID: $Id$
3  *
4  * libhal.c : HAL daemon C convenience library
5  *
6  * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
7  * Copyright (C) 2007 Codethink Ltd. Author Rob Taylor <rob.taylor@codethink.co.uk>
8  *
9  * Licensed under the Academic Free License version 2.1
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307	 USA
24  *
25  **************************************************************************/
26 
27 #ifdef HAVE_CONFIG_H
28 #  include <config.h>
29 #endif
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <dbus/dbus.h>
35 
36 #include "libhal.h"
37 
38 #ifdef ENABLE_NLS
39 # include <libintl.h>
40 # define _(String) dgettext (GETTEXT_PACKAGE, String)
41 # ifdef gettext_noop
42 #   define N_(String) gettext_noop (String)
43 # else
44 #   define N_(String) (String)
45 # endif
46 #else
47 /* Stubs that do something close enough.  */
48 # define textdomain(String) (String)
49 # define gettext(String) (String)
50 # define dgettext(Domain,Message) (Message)
51 # define dcgettext(Domain,Message,Type) (Message)
52 # define bindtextdomain(Domain,Directory) (Domain)
53 # define _(String)
54 # define N_(String) (String)
55 #endif
56 
57 /**
58  * LIBHAL_CHECK_PARAM_VALID:
59  * @_param_: the prameter to check for
60  * @_name_:  the name of the prameter (for debug output)
61  * @_ret_:   what to use for return value if the prameter is NULL
62  *
63  * Handy macro for checking whether a parameter is valid and not NULL.
64  */
65 #define LIBHAL_CHECK_PARAM_VALID(_param_,_name_,_ret_)				\
66 	do {									\
67 		if (_param_ == NULL) {						\
68 			fprintf (stderr,					\
69 				 "%s %d : invalid paramater. %s is NULL.\n",  	\
70 				 __FILE__, __LINE__, _name_);	 		\
71 			return _ret_;						\
72 		}								\
73 	} while(0)
74 
75 
76 static char **libhal_get_string_array_from_iter (DBusMessageIter *iter, int *num_elements);
77 
78 static dbus_bool_t libhal_property_fill_value_from_variant (LibHalProperty *p, DBusMessageIter *var_iter);
79 
80 
81 
82 /**
83  * libhal_free_string_array:
84  * @str_array: the array to be freed
85  *
86  * Frees a NULL-terminated array of strings. If passed NULL, does nothing.
87  */
88 void
89 libhal_free_string_array (char **str_array)
90 {
91 	if (str_array != NULL) {
92 		int i;
93 
94 		for (i = 0; str_array[i] != NULL; i++) {
95 			free (str_array[i]);
96 			str_array[i] = NULL;
97 		}
98 		free (str_array);
99 		str_array = NULL;
100 	}
101 }
102 
103 
104 /**
105  * libhal_get_string_array_from_iter:
106  * @iter: the message iterator to extract the strings from
107  * @num_elements: pointer to an integer where to store number of elements (can be NULL)
108  *
109  * Creates a NULL terminated array of strings from a dbus message iterator.
110  *
111  * Returns: pointer to the string array
112  */
113 static char **
114 libhal_get_string_array_from_iter (DBusMessageIter *iter, int *num_elements)
115 {
116 	int count;
117 	char **buffer;
118 
119 	count = 0;
120 	buffer = (char **)malloc (sizeof (char *) * 8);
121 
122 	if (buffer == NULL)
123 		goto oom;
124 
125 	buffer[0] = NULL;
126 	while (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_STRING) {
127 		const char *value;
128 		char *str;
129 
130 		if ((count % 8) == 0 && count != 0) {
131 			buffer = realloc (buffer, sizeof (char *) * (count + 8));
132 			if (buffer == NULL)
133 				goto oom;
134 		}
135 
136 		dbus_message_iter_get_basic (iter, &value);
137 		str = strdup (value);
138 		if (str == NULL)
139 			goto oom;
140 
141 		buffer[count] = str;
142 
143 		dbus_message_iter_next(iter);
144 		count++;
145 	}
146 
147 	if ((count % 8) == 0) {
148 		buffer = realloc (buffer, sizeof (char *) * (count + 1));
149 		if (buffer == NULL)
150 			goto oom;
151 	}
152 
153 	buffer[count] = NULL;
154 	if (num_elements != NULL)
155 		*num_elements = count;
156 	return buffer;
157 
158 oom:
159 	fprintf (stderr, "%s %d : error allocating memory\n", __FILE__, __LINE__);
160 	return NULL;
161 
162 }
163 
164 /**
165  * libhal_free_string:
166  * @str: the nul-terminated sting to free
167  *
168  * Used to free strings returned by libhal.
169  */
170 void
171 libhal_free_string (char *str)
172 {
173 	if (str != NULL) {
174 		free (str);
175 		str = NULL;
176 	}
177 }
178 
179 
180 /**
181  * LibHalPropertySet:
182  *
183  * Represents a set of properties. Opaque; use the
184  * libhal_property_set_*() family of functions to access it.
185  */
186 struct LibHalPropertySet_s {
187 	unsigned int num_properties; /**< Number of properties in set */
188 	LibHalProperty *properties_head;
189 				     /**< Pointer to first property or NULL
190 				      *	  if there are no properties */
191 };
192 
193 /**
194  * LibHalProperty:
195  *
196  * Represents a property. Opaque.
197  */
198 struct LibHalProperty_s {
199 	int type;		     /**< Type of property */
200 	char *key;		     /**< ASCII string */
201 
202 	/** Possible values of the property */
203 	union {
204 		char *str_value;     /**< UTF-8 zero-terminated string */
205 		dbus_int32_t int_value;
206 				     /**< 32-bit signed integer */
207 		dbus_uint64_t uint64_value;
208 				     /**< 64-bit unsigned integer */
209 		double double_value; /**< IEEE754 double precision float */
210 		dbus_bool_t bool_value;
211 				     /**< Truth value */
212 
213 		char **strlist_value; /**< List of UTF-8 zero-terminated strings */
214 	} v;
215 
216 	LibHalProperty *next;	     /**< Next property or NULL if this is
217 				      *	  the last */
218 };
219 
220 /**
221  * LibHalContext:
222  *
223  * Context for connection to the HAL daemon. Opaque, use the
224  * libhal_ctx_*() family of functions to access it.
225  */
226 struct LibHalContext_s {
227 	DBusConnection *connection;           /**< D-BUS connection */
228 	dbus_bool_t is_initialized;           /**< Are we initialised */
229 	dbus_bool_t is_shutdown;              /**< Have we been shutdown */
230 	dbus_bool_t cache_enabled;            /**< Is the cache enabled */
231 	dbus_bool_t is_direct;                /**< Whether the connection to hald is direct */
232 
233 	/** Device added */
234 	LibHalDeviceAdded device_added;
235 
236 	/** Device removed */
237 	LibHalDeviceRemoved device_removed;
238 
239 	/** Device got a new capability */
240 	LibHalDeviceNewCapability device_new_capability;
241 
242 	/** Device got a new capability */
243 	LibHalDeviceLostCapability device_lost_capability;
244 
245 	/** A property of a device changed  */
246 	LibHalDevicePropertyModified device_property_modified;
247 
248 	/** A non-continous event on the device occured  */
249 	LibHalDeviceCondition device_condition;
250 
251 	void *user_data;                      /**< User data */
252 };
253 
254 /**
255  * libhal_ctx_set_user_data:
256  * @ctx: the context for the connection to hald
257  * @user_data: user data
258  *
259  * Set user data for the context.
260  *
261  * Returns: TRUE if user data was successfully set, FALSE if otherwise
262  */
263 dbus_bool_t
264 libhal_ctx_set_user_data(LibHalContext *ctx, void *user_data)
265 {
266 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
267 	ctx->user_data = user_data;
268 	return TRUE;
269 }
270 
271 /**
272  * libhal_ctx_get_user_data:
273  * @ctx: the context for the connection to hald
274  *
275  * Get user data for the context.
276  *
277  * Returns: opaque pointer stored through libhal_ctx_set_user_data() or NULL if not set.
278  */
279 void*
280 libhal_ctx_get_user_data(LibHalContext *ctx)
281 {
282 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
283 	return ctx->user_data;
284 }
285 
286 
287 /**
288  * libhal_property_fill_value_from_variant:
289  * @p: the property to fill in
290  * @var_iter: variant iterator to extract the value from
291  *
292  * Fills in the value for the LibHalProperty given a variant iterator.
293  *
294  * Returns: Whether the value was put in.
295  */
296 static dbus_bool_t
297 libhal_property_fill_value_from_variant (LibHalProperty *p, DBusMessageIter *var_iter)
298 {
299 	DBusMessageIter iter_array;
300 	switch (p->type) {
301 	case DBUS_TYPE_ARRAY:
302 		if (dbus_message_iter_get_element_type (var_iter) != DBUS_TYPE_STRING)
303 			return FALSE;
304 
305 		dbus_message_iter_recurse (var_iter, &iter_array);
306 		p->v.strlist_value = libhal_get_string_array_from_iter (&iter_array, NULL);
307 
308 		p->type = LIBHAL_PROPERTY_TYPE_STRLIST;
309 
310 		break;
311 	case DBUS_TYPE_STRING:
312 	{
313 		const char *v;
314 
315 		dbus_message_iter_get_basic (var_iter, &v);
316 
317 		p->v.str_value = strdup (v);
318 		if (p->v.str_value == NULL)
319 			return FALSE;
320 		p->type = LIBHAL_PROPERTY_TYPE_STRING;
321 
322 		break;
323 	}
324 	case DBUS_TYPE_INT32:
325 	{
326 		dbus_int32_t v;
327 
328 		dbus_message_iter_get_basic (var_iter, &v);
329 
330 		p->v.int_value = v;
331 		p->type = LIBHAL_PROPERTY_TYPE_INT32;
332 
333 		break;
334 	}
335 	case DBUS_TYPE_UINT64:
336 	{
337 		dbus_uint64_t v;
338 
339 		dbus_message_iter_get_basic (var_iter, &v);
340 
341 		p->v.uint64_value = v;
342 		p->type = LIBHAL_PROPERTY_TYPE_UINT64;
343 
344 		break;
345 	}
346 	case DBUS_TYPE_DOUBLE:
347 	{
348 		double v;
349 
350 		dbus_message_iter_get_basic (var_iter, &v);
351 
352 		p->v.double_value = v;
353 		p->type = LIBHAL_PROPERTY_TYPE_DOUBLE;
354 
355 		break;
356 	}
357 	case DBUS_TYPE_BOOLEAN:
358 	{
359 		double v;
360 
361 		dbus_message_iter_get_basic (var_iter, &v);
362 
363 		p->v.double_value = v;
364 		p->type = LIBHAL_PROPERTY_TYPE_BOOLEAN;
365 
366 		break;
367 	}
368 	default:
369 		/** @todo  report error */
370 		break;
371 	}
372 
373 	return TRUE;
374 }
375 
376 /**
377  * libhal_device_get_all_properties:
378  * @ctx: the context for the connection to hald
379  * @udi: the Unique id of device
380  * @error: pointer to an initialized dbus error object for returning errors or NULL
381  *
382  * Retrieve all the properties on a device.
383  *
384  * Returns: An object represent all properties. Must be freed with libhal_free_property_set().
385  */
386 LibHalPropertySet *
387 libhal_device_get_all_properties (LibHalContext *ctx, const char *udi, DBusError *error)
388 {
389 	DBusMessage *message;
390 	DBusMessage *reply;
391 	DBusMessageIter reply_iter;
392 	DBusMessageIter dict_iter;
393 	LibHalPropertySet *result;
394 	LibHalProperty *p_last;
395 	DBusError _error;
396 
397 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
398 
399 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
400 						"org.freedesktop.Hal.Device",
401 						"GetAllProperties");
402 
403 	if (message == NULL) {
404 		fprintf (stderr,
405 			 "%s %d : Couldn't allocate D-BUS message\n",
406 			 __FILE__, __LINE__);
407 		return NULL;
408 	}
409 
410 	dbus_error_init (&_error);
411 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
412 							   message, -1,
413 							   &_error);
414 
415 	dbus_move_error (&_error, error);
416 	if (error != NULL && dbus_error_is_set (error)) {
417 		fprintf (stderr,
418 			 "%s %d : %s\n",
419 			 __FILE__, __LINE__, error->message);
420 
421 		dbus_message_unref (message);
422 		return NULL;
423 	}
424 
425 	if (reply == NULL) {
426 		dbus_message_unref (message);
427 		return NULL;
428 	}
429 
430 	dbus_message_iter_init (reply, &reply_iter);
431 
432 	result = malloc (sizeof (LibHalPropertySet));
433 	if (result == NULL)
434 		goto oom;
435 /*
436     result->properties = malloc(sizeof(LibHalProperty)*result->num_properties);
437     if( result->properties==NULL )
438     {
439     /// @todo  cleanup
440 	return NULL;
441     }
442 */
443 
444 	result->properties_head = NULL;
445 	result->num_properties = 0;
446 
447 	if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY  &&
448 	    dbus_message_iter_get_element_type (&reply_iter) != DBUS_TYPE_DICT_ENTRY) {
449 		fprintf (stderr, "%s %d : error, expecting an array of dict entries\n",
450 			 __FILE__, __LINE__);
451 		dbus_message_unref (message);
452 		dbus_message_unref (reply);
453 		return NULL;
454 	}
455 
456 	dbus_message_iter_recurse (&reply_iter, &dict_iter);
457 
458 	p_last = NULL;
459 
460 	while (dbus_message_iter_get_arg_type (&dict_iter) == DBUS_TYPE_DICT_ENTRY)
461 	{
462 		DBusMessageIter dict_entry_iter, var_iter;
463 		const char *key;
464 		LibHalProperty *p;
465 
466 		dbus_message_iter_recurse (&dict_iter, &dict_entry_iter);
467 
468 		dbus_message_iter_get_basic (&dict_entry_iter, &key);
469 
470 		p = malloc (sizeof (LibHalProperty));
471 		if (p == NULL)
472 			goto oom;
473 
474 		p->next = NULL;
475 
476 		if (result->num_properties == 0)
477 			result->properties_head = p;
478 
479 		if (p_last != NULL)
480 			p_last->next = p;
481 
482 		p_last = p;
483 
484 		p->key = strdup (key);
485 		if (p->key == NULL)
486 			goto oom;
487 
488 		dbus_message_iter_next (&dict_entry_iter);
489 
490 		dbus_message_iter_recurse (&dict_entry_iter, &var_iter);
491 
492 
493 		p->type = dbus_message_iter_get_arg_type (&var_iter);
494 
495 		result->num_properties++;
496 
497 		if(!libhal_property_fill_value_from_variant (p, &var_iter))
498 			goto oom;
499 
500 		dbus_message_iter_next (&dict_iter);
501 	}
502 
503 	dbus_message_unref (message);
504 	dbus_message_unref (reply);
505 
506 	return result;
507 
508 oom:
509 	fprintf (stderr,
510 		"%s %d : error allocating memory\n",
511 		 __FILE__, __LINE__);
512 		/** @todo FIXME cleanup */
513 	return NULL;
514 }
515 
516 /**
517  * libhal_free_property_set:
518  * @set: property-set to free
519  *
520  * Free a property set earlier obtained with libhal_device_get_all_properties().
521  */
522 void
523 libhal_free_property_set (LibHalPropertySet * set)
524 {
525 	LibHalProperty *p;
526 	LibHalProperty *q;
527 
528 	if (set == NULL)
529 		return;
530 
531 	for (p = set->properties_head; p != NULL; p = q) {
532 		free (p->key);
533 		if (p->type == DBUS_TYPE_STRING)
534 			free (p->v.str_value);
535 		if (p->type == LIBHAL_PROPERTY_TYPE_STRLIST)
536 			libhal_free_string_array (p->v.strlist_value);
537 		q = p->next;
538 		free (p);
539 	}
540 	free (set);
541 }
542 
543 /**
544  * libhal_property_set_get_num_elems:
545  * @set: property set to consider
546  *
547  * Get the number of properties in a property set.
548  *
549  * Returns: number of properties in given property set
550  */
551 unsigned int
552 libhal_property_set_get_num_elems (LibHalPropertySet *set)
553 {
554 	unsigned int num_elems;
555 	LibHalProperty *p;
556 
557 	if (set == NULL)
558 		return 0;
559 
560 	num_elems = 0;
561 	for (p = set->properties_head; p != NULL; p = p->next)
562 		num_elems++;
563 
564 	return num_elems;
565 }
566 
567 static LibHalProperty *
568 property_set_lookup (const LibHalPropertySet *set, const char *key)
569 {
570 	LibHalProperty *p;
571 
572 	LIBHAL_CHECK_PARAM_VALID(set, "*set", NULL);
573 	LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL);
574 
575 	for (p = set->properties_head; p != NULL; p = p->next)
576 		if (strcmp (key, p->key) == 0)
577 			return p;
578 
579 	return NULL;
580 }
581 
582 /**
583  * libhal_ps_get_type:
584  * @set: property set
585  * @key: name of property to inspect
586  *
587  * Get the type of a given property.
588  *
589  * Returns: the #LibHalPropertyType of the given property,
590  * LIBHAL_PROPERTY_TYPE_INVALID if property is not in the set
591  */
592 LibHalPropertyType
593 libhal_ps_get_type (const LibHalPropertySet *set, const char *key)
594 {
595 	LibHalProperty *p = property_set_lookup (set, key);
596 
597 	LIBHAL_CHECK_PARAM_VALID(set, "*set", LIBHAL_PROPERTY_TYPE_INVALID);
598 	LIBHAL_CHECK_PARAM_VALID(key, "*key", LIBHAL_PROPERTY_TYPE_INVALID);
599 
600 	p = property_set_lookup (set, key);
601 	if (p) return p->type;
602 	else return LIBHAL_PROPERTY_TYPE_INVALID;
603 }
604 
605 /**
606  * libhal_ps_get_string:
607  * @set: property set
608  * @key: name of property to inspect
609  *
610  * Get the value of a property of type string.
611  *
612  * Returns: UTF8 nul-terminated string. This pointer is only valid
613  * until libhal_free_property_set() is invoked on the property set
614  * this property belongs to. NULL if property is not in the set or not a string
615  */
616 const char *
617 libhal_ps_get_string  (const LibHalPropertySet *set, const char *key)
618 {
619 	LibHalProperty *p;
620 
621 	LIBHAL_CHECK_PARAM_VALID(set, "*set", NULL);
622 	LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL);
623 
624 	p = property_set_lookup (set, key);
625 	if (p && p->type == LIBHAL_PROPERTY_TYPE_STRING)
626 		return p->v.str_value;
627 	else return NULL;
628 }
629 
630 /**
631  * libhal_ps_get_int:
632  * @set: property set
633  * @key: name of property to inspect
634  *
635  * Get the value of a property of type signed integer.
636  *
637  * Returns: property value (32-bit signed integer)
638  */
639 dbus_int32_t
640 libhal_ps_get_int32 (const LibHalPropertySet *set, const char *key)
641 {
642 	LibHalProperty *p;
643 
644 	LIBHAL_CHECK_PARAM_VALID(set, "*set", 0);
645 	LIBHAL_CHECK_PARAM_VALID(key, "*key", 0);
646 
647 	p = property_set_lookup (set, key);
648 	if (p && p->type == LIBHAL_PROPERTY_TYPE_INT32)
649 		return p->v.int_value;
650 	else return 0;
651 }
652 
653 /**
654  * libhal_ps_get_uint64:
655  * @set: property set
656  * @key: name of property to inspect
657  *
658  * Get the value of a property of type unsigned integer.
659  *
660  * Returns: property value (64-bit unsigned integer)
661  */
662 dbus_uint64_t
663 libhal_ps_get_uint64 (const LibHalPropertySet *set, const char *key)
664 {
665 	LibHalProperty *p;
666 
667 	LIBHAL_CHECK_PARAM_VALID(set, "*set", 0);
668 	LIBHAL_CHECK_PARAM_VALID(key, "*key", 0);
669 
670 	p = property_set_lookup (set, key);
671 	if (p && p->type == LIBHAL_PROPERTY_TYPE_UINT64)
672 		return p->v.uint64_value;
673 	else return 0;
674 }
675 
676 /**
677  * libhal_ps_get_double:
678  * @set: property set
679  * @key: name of property to inspect
680  *
681  * Get the value of a property of type double.
682  *
683  * Returns: property value (IEEE754 double precision float)
684  */
685 double
686 libhal_ps_get_double (const LibHalPropertySet *set, const char *key)
687 {
688 	LibHalProperty *p;
689 
690 	LIBHAL_CHECK_PARAM_VALID(set, "*set", 0.0);
691 	LIBHAL_CHECK_PARAM_VALID(key, "*key", 0.0);
692 
693 	p = property_set_lookup (set, key);
694 	if (p && p->type == LIBHAL_PROPERTY_TYPE_DOUBLE)
695 		return p->v.double_value;
696 	else return 0.0;
697 }
698 
699 /**
700  * libhal_ps_get_bool:
701  * @set: property set
702  * @key: name of property to inspect
703  *
704  * Get the value of a property of type bool.
705  *
706  * Returns: property value (bool)
707  */
708 dbus_bool_t
709 libhal_ps_get_bool (const LibHalPropertySet *set, const char *key)
710 {
711 	LibHalProperty *p;
712 
713 	LIBHAL_CHECK_PARAM_VALID(set, "*set", FALSE);
714 	LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE);
715 
716 	p = property_set_lookup (set, key);
717 	if (p && p->type == LIBHAL_PROPERTY_TYPE_BOOLEAN)
718 		return p->v.bool_value;
719 	else return FALSE;
720 }
721 
722 /**
723  * libhal_ps_get_strlist:
724  * @set: property set
725  * @key: name of property to inspect
726  *
727  * Get the value of a property of type string list.
728  *
729  * Returns: pointer to array of strings, this is owned by the property set
730  */
731 const char *const *
732 libhal_ps_get_strlist (const LibHalPropertySet *set, const char *key)
733 {
734 	LibHalProperty *p;
735 
736 	LIBHAL_CHECK_PARAM_VALID(set, "*set", NULL);
737 	LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL);
738 
739 	p = property_set_lookup (set, key);
740 	if (p && p->type == LIBHAL_PROPERTY_TYPE_STRLIST)
741 		return (const char *const *) p->v.strlist_value;
742 	else return NULL;
743 }
744 
745 
746 /**
747  * libhal_psi_init:
748  * @iter: iterator object
749  * @set: property set to iterate over
750  *
751  * Initialize a property set iterator.
752  *
753  */
754 void
755 libhal_psi_init (LibHalPropertySetIterator * iter, LibHalPropertySet * set)
756 {
757 	if (set == NULL)
758 		return;
759 
760 	iter->set = set;
761 	iter->idx = 0;
762 	iter->cur_prop = set->properties_head;
763 }
764 
765 
766 /**
767  * libhal_psi_has_more:
768  * @iter: iterator object
769  *
770  * Determine whether there are more properties to iterate over.
771  *
772  * Returns: TRUE if there are more properties, FALSE otherwise.
773  */
774 dbus_bool_t
775 libhal_psi_has_more (LibHalPropertySetIterator * iter)
776 {
777 	return iter->idx < iter->set->num_properties;
778 }
779 
780 /**
781  * libhal_psi_next:
782  * @iter: iterator object
783  *
784  * Advance iterator to next property.
785  */
786 void
787 libhal_psi_next (LibHalPropertySetIterator * iter)
788 {
789 	iter->idx++;
790 	iter->cur_prop = iter->cur_prop->next;
791 }
792 
793 /**
794  * libhal_psi_get_type:
795  * @iter: iterator object
796  *
797  * Get type of property.
798  *
799  * Returns: the property type at the iterator's position
800  */
801 LibHalPropertyType
802 libhal_psi_get_type (LibHalPropertySetIterator * iter)
803 {
804 	return iter->cur_prop->type;
805 }
806 
807 /**
808  * libhal_psi_get_key:
809  * @iter: iterator object
810  *
811  * Get the key of a property.
812  *
813  * Returns: ASCII nul-terminated string. This pointer is only valid
814  * until libhal_free_property_set() is invoked on the property set
815  * this property belongs to.
816  */
817 char *
818 libhal_psi_get_key (LibHalPropertySetIterator * iter)
819 {
820 	return iter->cur_prop->key;
821 }
822 
823 /**
824  * libhal_psi_get_string:
825  * @iter: iterator object
826  *
827  * Get the value of a property of type string.
828  *
829  * Returns: UTF8 nul-terminated string. This pointer is only valid
830  * until libhal_free_property_set() is invoked on the property set
831  * this property belongs to.
832  */
833 char *
834 libhal_psi_get_string (LibHalPropertySetIterator * iter)
835 {
836 	return iter->cur_prop->v.str_value;
837 }
838 
839 /**
840  * libhal_psi_get_int:
841  * @iter: iterator object
842  *
843  * Get the value of a property of type signed integer.
844  *
845  * Returns: property value (32-bit signed integer)
846  */
847 dbus_int32_t
848 libhal_psi_get_int (LibHalPropertySetIterator * iter)
849 {
850 	return iter->cur_prop->v.int_value;
851 }
852 
853 /**
854  * libhal_psi_get_uint64:
855  * @iter: iterator object
856  *
857  * Get the value of a property of type unsigned integer.
858  *
859  * Returns: property value (64-bit unsigned integer)
860  */
861 dbus_uint64_t
862 libhal_psi_get_uint64 (LibHalPropertySetIterator * iter)
863 {
864 	return iter->cur_prop->v.uint64_value;
865 }
866 
867 /**
868  * libhal_psi_get_double:
869  * @iter: iterator object
870  *
871  * Get the value of a property of type double.
872  *
873  * Returns: property value (IEEE754 double precision float)
874  */
875 double
876 libhal_psi_get_double (LibHalPropertySetIterator * iter)
877 {
878 	return iter->cur_prop->v.double_value;
879 }
880 
881 /**
882  * libhal_psi_get_bool:
883  * @iter: iterator object
884  *
885  * Get the value of a property of type bool.
886  *
887  * Returns: property value (bool)
888  */
889 dbus_bool_t
890 libhal_psi_get_bool (LibHalPropertySetIterator * iter)
891 {
892 	return iter->cur_prop->v.bool_value;
893 }
894 
895 /**
896  * libhal_psi_get_strlist:
897  * @iter: iterator object
898  *
899  * Get the value of a property of type string list.
900  *
901  * Returns: pointer to array of strings
902  */
903 char **
904 libhal_psi_get_strlist (LibHalPropertySetIterator * iter)
905 {
906 	return iter->cur_prop->v.strlist_value;
907 }
908 
909 
910 static DBusHandlerResult
911 filter_func (DBusConnection * connection,
912 	     DBusMessage * message, void *user_data)
913 {
914 	const char *object_path;
915 	DBusError error;
916 	LibHalContext *ctx = (LibHalContext *) user_data;
917 
918 	if (ctx->is_shutdown)
919 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
920 
921 	dbus_error_init (&error);
922 
923 	object_path = dbus_message_get_path (message);
924 
925 	/*printf("*** in filter_func, object_path=%s\n", object_path);*/
926 
927 	if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager",
928 				    "DeviceAdded")) {
929 		char *udi;
930 		if (dbus_message_get_args (message, &error,
931 					   DBUS_TYPE_STRING, &udi,
932 					   DBUS_TYPE_INVALID)) {
933 			if (ctx->device_added != NULL) {
934 				ctx->device_added (ctx, udi);
935 			}
936 		} else {
937 			LIBHAL_FREE_DBUS_ERROR(&error);
938 		}
939 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
940 	} else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager", "DeviceRemoved")) {
941 		char *udi;
942 		if (dbus_message_get_args (message, &error,
943 					   DBUS_TYPE_STRING, &udi,
944 					   DBUS_TYPE_INVALID)) {
945 			if (ctx->device_removed != NULL) {
946 				ctx->device_removed (ctx, udi);
947 			}
948 		} else {
949 			LIBHAL_FREE_DBUS_ERROR(&error);
950 		}
951 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
952 	} else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager","NewCapability")) {
953 		char *udi;
954 		char *capability;
955 		if (dbus_message_get_args (message, &error,
956 					   DBUS_TYPE_STRING, &udi,
957 					   DBUS_TYPE_STRING, &capability,
958 					   DBUS_TYPE_INVALID)) {
959 			if (ctx->device_new_capability != NULL) {
960 				ctx->device_new_capability (ctx, udi, capability);
961 			}
962 		} else {
963 			LIBHAL_FREE_DBUS_ERROR(&error);
964 		}
965 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
966 	} else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Device", "Condition")) {
967 		char *condition_name;
968 		char *condition_detail;
969 		if (dbus_message_get_args (message, &error,
970 					   DBUS_TYPE_STRING, &condition_name,
971 					   DBUS_TYPE_STRING, &condition_detail,
972 					   DBUS_TYPE_INVALID)) {
973 			if (ctx->device_condition != NULL) {
974 				ctx->device_condition (ctx, object_path, condition_name, condition_detail);
975 			}
976 		} else {
977 			LIBHAL_FREE_DBUS_ERROR(&error);
978 		}
979 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
980 	} else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Device", "PropertyModified")) {
981 		if (ctx->device_property_modified != NULL) {
982 			int i;
983 			char *key;
984 			dbus_bool_t removed;
985 			dbus_bool_t added;
986 			int num_modifications;
987 			DBusMessageIter iter;
988 			DBusMessageIter iter_array;
989 
990 			dbus_message_iter_init (message, &iter);
991 			dbus_message_iter_get_basic (&iter, &num_modifications);
992 			dbus_message_iter_next (&iter);
993 
994 			dbus_message_iter_recurse (&iter, &iter_array);
995 
996 			for (i = 0; i < num_modifications; i++) {
997 				DBusMessageIter iter_struct;
998 
999 				dbus_message_iter_recurse (&iter_array, &iter_struct);
1000 
1001 				dbus_message_iter_get_basic (&iter_struct, &key);
1002 				dbus_message_iter_next (&iter_struct);
1003 				dbus_message_iter_get_basic (&iter_struct, &removed);
1004 				dbus_message_iter_next (&iter_struct);
1005 				dbus_message_iter_get_basic (&iter_struct, &added);
1006 
1007 				ctx->device_property_modified (ctx,
1008 							       object_path,
1009 							       key, removed,
1010 							       added);
1011 
1012 				dbus_message_iter_next (&iter_array);
1013 			}
1014 
1015 		}
1016 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1017 	}
1018 
1019 	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1020 }
1021 
1022 /* for i18n purposes */
1023 static dbus_bool_t libhal_already_initialized_once = FALSE;
1024 
1025 
1026 /**
1027  * libhal_get_all_devices:
1028  * @ctx: the context for the connection to hald
1029  * @num_devices: the number of devices will be stored here
1030  * @error: pointer to an initialized dbus error object for returning errors or NULL
1031  *
1032  * Get all devices in the Global Device List (GDL).
1033  *
1034  * Returns: An array of device identifiers terminated with NULL. It is
1035  * the responsibility of the caller to free with
1036  * libhal_free_string_array(). If an error occurs NULL is returned.
1037  */
1038 char **
1039 libhal_get_all_devices (LibHalContext *ctx, int *num_devices, DBusError *error)
1040 {
1041 	DBusMessage *message;
1042 	DBusMessage *reply;
1043 	DBusMessageIter iter_array, reply_iter;
1044 	char **hal_device_names;
1045 	DBusError _error;
1046 
1047 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
1048 
1049 	*num_devices = 0;
1050 
1051 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
1052 						"/org/freedesktop/Hal/Manager",
1053 						"org.freedesktop.Hal.Manager",
1054 						"GetAllDevices");
1055 	if (message == NULL) {
1056 		fprintf (stderr, "%s %d : Could not allocate D-BUS message\n", __FILE__, __LINE__);
1057 		return NULL;
1058 	}
1059 
1060 	dbus_error_init (&_error);
1061 	reply = dbus_connection_send_with_reply_and_block (ctx->connection, message, -1, &_error);
1062 
1063 	dbus_move_error (&_error, error);
1064 	if (error != NULL && dbus_error_is_set (error)) {
1065 		dbus_message_unref (message);
1066 		return NULL;
1067 	}
1068 	if (reply == NULL) {
1069 		dbus_message_unref (message);
1070 		return NULL;
1071 	}
1072 
1073 	/* now analyze reply */
1074 	dbus_message_iter_init (reply, &reply_iter);
1075 
1076 	if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) {
1077 		fprintf (stderr, "%s %d : wrong reply from hald.  Expecting an array.\n", __FILE__, __LINE__);
1078 		return NULL;
1079 	}
1080 
1081 	dbus_message_iter_recurse (&reply_iter, &iter_array);
1082 
1083 	hal_device_names = libhal_get_string_array_from_iter (&iter_array, num_devices);
1084 
1085 	dbus_message_unref (reply);
1086 	dbus_message_unref (message);
1087 
1088 	return hal_device_names;
1089 }
1090 
1091 /**
1092  * libhal_device_get_property_type:
1093  * @ctx: the context for the connection to hald
1094  * @udi: the Unique Device Id
1095  * @key: name of the property
1096  * @error: pointer to an initialized dbus error object for returning errors or NULL
1097  *
1098  * Query a property type of a device.
1099  *
1100  * Returns: A LibHalPropertyType. LIBHAL_PROPERTY_TYPE_INVALID is
1101  * return if the property doesn't exist.
1102  */
1103 LibHalPropertyType
1104 libhal_device_get_property_type (LibHalContext *ctx, const char *udi, const char *key, DBusError *error)
1105 {
1106 	DBusMessage *message;
1107 	DBusMessage *reply;
1108 	DBusMessageIter iter, reply_iter;
1109 	int type;
1110 	DBusError _error;
1111 
1112 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, LIBHAL_PROPERTY_TYPE_INVALID); /* or return NULL? */
1113 
1114 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
1115 						"org.freedesktop.Hal.Device",
1116 						"GetPropertyType");
1117 	if (message == NULL) {
1118 		fprintf (stderr, "%s %d : Couldn't allocate D-BUS message\n", __FILE__, __LINE__);
1119 		return LIBHAL_PROPERTY_TYPE_INVALID;
1120 	}
1121 
1122 	dbus_message_iter_init_append (message, &iter);
1123 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
1124 
1125 	dbus_error_init (&_error);
1126 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
1127 							   message, -1,
1128 							   &_error);
1129 
1130 	dbus_move_error (&_error, error);
1131 	if (error != NULL && dbus_error_is_set (error)) {
1132 		dbus_message_unref (message);
1133 		return LIBHAL_PROPERTY_TYPE_INVALID;
1134 	}
1135 	if (reply == NULL) {
1136 		dbus_message_unref (message);
1137 		return LIBHAL_PROPERTY_TYPE_INVALID;
1138 	}
1139 
1140 	dbus_message_iter_init (reply, &reply_iter);
1141 	dbus_message_iter_get_basic (&reply_iter, &type);
1142 
1143 	dbus_message_unref (message);
1144 	dbus_message_unref (reply);
1145 
1146 	return type;
1147 }
1148 
1149 /**
1150  * libhal_device_get_property_strlist:
1151  * @ctx: the context for the connection to hald
1152  * @udi: unique Device Id
1153  * @key: name of the property
1154  * @error: pointer to an initialized dbus error object for returning errors or NULL
1155  *
1156  * Get the value of a property of type string list.
1157  *
1158  * Returns: Array of pointers to UTF8 nul-terminated strings
1159  * terminated by NULL. The caller is responsible for freeing this
1160  * string array with the function libhal_free_string_array(). Returns
1161  * NULL if the property didn't exist or we are OOM
1162  */
1163 char **
1164 libhal_device_get_property_strlist (LibHalContext *ctx, const char *udi, const char *key, DBusError *error)
1165 {
1166 	DBusMessage *message;
1167 	DBusMessage *reply;
1168 	DBusMessageIter iter, iter_array, reply_iter;
1169 	char **our_strings;
1170 	DBusError _error;
1171 
1172 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
1173 
1174 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
1175 						"org.freedesktop.Hal.Device",
1176 						"GetPropertyStringList");
1177 	if (message == NULL) {
1178 		fprintf (stderr,
1179 			 "%s %d : Couldn't allocate D-BUS message\n",
1180 			 __FILE__, __LINE__);
1181 		return NULL;
1182 	}
1183 
1184 	dbus_message_iter_init_append (message, &iter);
1185 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
1186 
1187 	dbus_error_init (&_error);
1188 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
1189 							   message, -1,
1190 							   &_error);
1191 
1192 	dbus_move_error (&_error, error);
1193 	if (error != NULL && dbus_error_is_set (error)) {
1194 		dbus_message_unref (message);
1195 		return NULL;
1196 	}
1197 	if (reply == NULL) {
1198 		dbus_message_unref (message);
1199 		return NULL;
1200 	}
1201 	/* now analyse reply */
1202 	dbus_message_iter_init (reply, &reply_iter);
1203 
1204 	if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) {
1205 		fprintf (stderr, "%s %d : wrong reply from hald.  Expecting an array.\n", __FILE__, __LINE__);
1206 		return NULL;
1207 	}
1208 
1209 	dbus_message_iter_recurse (&reply_iter, &iter_array);
1210 
1211 	our_strings = libhal_get_string_array_from_iter (&iter_array, NULL);
1212 
1213 	dbus_message_unref (reply);
1214 	dbus_message_unref (message);
1215 
1216 	return our_strings;
1217 }
1218 
1219 /**
1220  * libhal_device_get_property_string:
1221  * @ctx: the context for the connection to hald
1222  * @udi: the Unique Device Id
1223  * @key: the name of the property
1224  * @error: pointer to an initialized dbus error object for returning errors or NULL
1225  *
1226  * Get the value of a property of type string.
1227  *
1228  * Returns: UTF8 nul-terminated string. The caller is responsible for
1229  * freeing this string with the function libhal_free_string(). Returns
1230  * NULL if the property didn't exist or we are OOM.
1231  */
1232 char *
1233 libhal_device_get_property_string (LibHalContext *ctx,
1234 				   const char *udi, const char *key, DBusError *error)
1235 {
1236 	DBusMessage *message;
1237 	DBusMessage *reply;
1238 	DBusMessageIter iter, reply_iter;
1239 	char *value;
1240 	char *dbus_str;
1241 	DBusError _error;
1242 
1243 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
1244 
1245 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
1246 						"org.freedesktop.Hal.Device",
1247 						"GetPropertyString");
1248 
1249 	if (message == NULL) {
1250 		fprintf (stderr,
1251 			 "%s %d : Couldn't allocate D-BUS message\n",
1252 			 __FILE__, __LINE__);
1253 		return NULL;
1254 	}
1255 
1256 	dbus_message_iter_init_append (message, &iter);
1257 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
1258 
1259 	dbus_error_init (&_error);
1260 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
1261 							   message, -1,
1262 							   &_error);
1263 
1264 	dbus_move_error (&_error, error);
1265 	if (error != NULL && dbus_error_is_set (error)) {
1266 		dbus_message_unref (message);
1267 		return NULL;
1268 	}
1269 	if (reply == NULL) {
1270 		dbus_message_unref (message);
1271 		return NULL;
1272 	}
1273 
1274 	dbus_message_iter_init (reply, &reply_iter);
1275 
1276 	/* now analyze reply */
1277 	if (dbus_message_iter_get_arg_type (&reply_iter) !=
1278 		   DBUS_TYPE_STRING) {
1279 		dbus_message_unref (message);
1280 		dbus_message_unref (reply);
1281 		return NULL;
1282 	}
1283 
1284 	dbus_message_iter_get_basic (&reply_iter, &dbus_str);
1285 	value = (char *) ((dbus_str != NULL) ? strdup (dbus_str) : NULL);
1286 	if (value == NULL) {
1287 		fprintf (stderr, "%s %d : error allocating memory\n",
1288 			 __FILE__, __LINE__);
1289 		/** @todo FIXME cleanup */
1290 		return NULL;
1291 	}
1292 
1293 	dbus_message_unref (message);
1294 	dbus_message_unref (reply);
1295 	return value;
1296 }
1297 
1298 /**
1299  * libhal_device_get_property_int:
1300  * @ctx: the context for the connection to hald
1301  * @udi: the Unique Device Id
1302  * @key: name of the property
1303  * @error: pointer to an initialized dbus error object for returning errors or NULL
1304  *
1305  * Get the value of a property of type integer.
1306  *
1307  * Returns: Property value (32-bit signed integer)
1308  */
1309 dbus_int32_t
1310 libhal_device_get_property_int (LibHalContext *ctx,
1311 				const char *udi, const char *key, DBusError *error)
1312 {
1313 	DBusMessage *message;
1314 	DBusMessage *reply;
1315 	DBusMessageIter iter, reply_iter;
1316 	dbus_int32_t value;
1317 	DBusError _error;
1318 
1319 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, -1);
1320 
1321 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
1322 						"org.freedesktop.Hal.Device",
1323 						"GetPropertyInteger");
1324 	if (message == NULL) {
1325 		fprintf (stderr,
1326 			 "%s %d : Couldn't allocate D-BUS message\n",
1327 			 __FILE__, __LINE__);
1328 		return -1;
1329 	}
1330 
1331 	dbus_message_iter_init_append (message, &iter);
1332 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
1333 
1334 	dbus_error_init (&_error);
1335 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
1336 							   message, -1,
1337 							   &_error);
1338 
1339 	dbus_move_error (&_error, error);
1340 	if (error != NULL && dbus_error_is_set (error)) {
1341 		dbus_message_unref (message);
1342 		return -1;
1343 	}
1344 	if (reply == NULL) {
1345 		dbus_message_unref (message);
1346 		return -1;
1347 	}
1348 
1349 	dbus_message_iter_init (reply, &reply_iter);
1350 
1351 	/* now analyze reply */
1352 	if (dbus_message_iter_get_arg_type (&reply_iter) !=
1353 		   DBUS_TYPE_INT32) {
1354 		fprintf (stderr,
1355 			 "%s %d : property '%s' for device '%s' is not "
1356 			 "of type integer\n", __FILE__, __LINE__, key,
1357 			 udi);
1358 		dbus_message_unref (message);
1359 		dbus_message_unref (reply);
1360 		return -1;
1361 	}
1362 	dbus_message_iter_get_basic (&reply_iter, &value);
1363 
1364 	dbus_message_unref (message);
1365 	dbus_message_unref (reply);
1366 	return value;
1367 }
1368 
1369 /**
1370  * libhal_device_get_property_uint64:
1371  * @ctx: the context for the connection to hald
1372  * @udi: the Unique Device Id
1373  * @key: name of the property
1374  * @error: pointer to an initialized dbus error object for returning errors or NULL
1375  *
1376  * Get the value of a property of type signed integer.
1377  *
1378  * Returns: Property value (64-bit unsigned integer)
1379  */
1380 dbus_uint64_t
1381 libhal_device_get_property_uint64 (LibHalContext *ctx,
1382 				   const char *udi, const char *key, DBusError *error)
1383 {
1384 	DBusMessage *message;
1385 	DBusMessage *reply;
1386 	DBusMessageIter iter, reply_iter;
1387 	dbus_uint64_t value;
1388 	DBusError _error;
1389 
1390 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, -1);
1391 
1392 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
1393 						"org.freedesktop.Hal.Device",
1394 						"GetPropertyInteger");
1395 	if (message == NULL) {
1396 		fprintf (stderr,
1397 			 "%s %d : Couldn't allocate D-BUS message\n",
1398 			 __FILE__, __LINE__);
1399 		return -1;
1400 	}
1401 
1402 	dbus_message_iter_init_append (message, &iter);
1403 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
1404 
1405 	dbus_error_init (&_error);
1406 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
1407 							   message, -1,
1408 							   &_error);
1409 
1410 	dbus_move_error (&_error, error);
1411 	if (error != NULL && dbus_error_is_set (error)) {
1412 		dbus_message_unref (message);
1413 		return -1;
1414 	}
1415 	if (reply == NULL) {
1416 		dbus_message_unref (message);
1417 		return -1;
1418 	}
1419 
1420 	dbus_message_iter_init (reply, &reply_iter);
1421 	/* now analyze reply */
1422 	if (dbus_message_iter_get_arg_type (&reply_iter) !=
1423 		   DBUS_TYPE_UINT64) {
1424 		fprintf (stderr,
1425 			 "%s %d : property '%s' for device '%s' is not "
1426 			 "of type integer\n", __FILE__, __LINE__, key,
1427 			 udi);
1428 		dbus_message_unref (message);
1429 		dbus_message_unref (reply);
1430 		return -1;
1431 	}
1432 	dbus_message_iter_get_basic (&reply_iter, &value);
1433 
1434 	dbus_message_unref (message);
1435 	dbus_message_unref (reply);
1436 	return value;
1437 }
1438 
1439 /**
1440  * libhal_device_get_property_double:
1441  * @ctx: the context for the connection to hald
1442  * @udi: the Unique Device Id
1443  * @key: name of the property
1444  * @error: pointer to an initialized dbus error object for returning errors or NULL
1445  *
1446  * Get the value of a property of type double.
1447  *
1448  * Returns: Property value (IEEE754 double precision float)
1449  */
1450 double
1451 libhal_device_get_property_double (LibHalContext *ctx,
1452 				   const char *udi, const char *key, DBusError *error)
1453 {
1454 	DBusMessage *message;
1455 	DBusMessage *reply;
1456 	DBusMessageIter iter, reply_iter;
1457 	double value;
1458 	DBusError _error;
1459 
1460 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, -1.0);
1461 
1462 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
1463 						"org.freedesktop.Hal.Device",
1464 						"GetPropertyDouble");
1465 	if (message == NULL) {
1466 		fprintf (stderr,
1467 			 "%s %d : Couldn't allocate D-BUS message\n",
1468 			 __FILE__, __LINE__);
1469 		return -1.0f;
1470 	}
1471 
1472 	dbus_message_iter_init_append (message, &iter);
1473 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
1474 
1475 	dbus_error_init (&_error);
1476 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
1477 							   message, -1,
1478 							   &_error);
1479 
1480 	dbus_move_error (&_error, error);
1481 	if (error != NULL && dbus_error_is_set (error)) {
1482 		dbus_message_unref (message);
1483 		return -1.0f;
1484 	}
1485 	if (reply == NULL) {
1486 		dbus_message_unref (message);
1487 		return -1.0f;
1488 	}
1489 
1490 	dbus_message_iter_init (reply, &reply_iter);
1491 
1492 	/* now analyze reply */
1493 	if (dbus_message_iter_get_arg_type (&reply_iter) !=
1494 		   DBUS_TYPE_DOUBLE) {
1495 		fprintf (stderr,
1496 			 "%s %d : property '%s' for device '%s' is not "
1497 			 "of type double\n", __FILE__, __LINE__, key, udi);
1498 		dbus_message_unref (message);
1499 		dbus_message_unref (reply);
1500 		return -1.0f;
1501 	}
1502 	dbus_message_iter_get_basic (&reply_iter, &value);
1503 
1504 	dbus_message_unref (message);
1505 	dbus_message_unref (reply);
1506 	return (double) value;
1507 }
1508 
1509 /**
1510  * libhal_device_get_property_bool:
1511  * @ctx: the context for the connection to hald
1512  * @udi: the Unique Device Id
1513  * @key: name of the property
1514  * @error: pointer to an initialized dbus error object for returning errors or NULL
1515  *
1516  * Get the value of a property of type bool.
1517  *
1518  * Returns: Property value (boolean)
1519  */
1520 dbus_bool_t
1521 libhal_device_get_property_bool (LibHalContext *ctx,
1522 				 const char *udi, const char *key, DBusError *error)
1523 {
1524 	DBusMessage *message;
1525 	DBusMessage *reply;
1526 	DBusMessageIter iter, reply_iter;
1527 	dbus_bool_t value;
1528 	DBusError _error;
1529 
1530 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
1531 
1532 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
1533 						"org.freedesktop.Hal.Device",
1534 						"GetPropertyBoolean");
1535 	if (message == NULL) {
1536 		fprintf (stderr,
1537 			 "%s %d : Couldn't allocate D-BUS message\n",
1538 			 __FILE__, __LINE__);
1539 		return FALSE;
1540 	}
1541 
1542 	dbus_message_iter_init_append (message, &iter);
1543 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
1544 
1545 	dbus_error_init (&_error);
1546 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
1547 							   message, -1,
1548 							   &_error);
1549 
1550 	dbus_move_error (&_error, error);
1551 	if (error != NULL && dbus_error_is_set (error)) {
1552 		dbus_message_unref (message);
1553 		return FALSE;
1554 	}
1555 	if (reply == NULL) {
1556 		dbus_message_unref (message);
1557 		return FALSE;
1558 	}
1559 
1560 	dbus_message_iter_init (reply, &reply_iter);
1561 
1562 	/* now analyze reply */
1563 	if (dbus_message_iter_get_arg_type (&reply_iter) !=
1564 		   DBUS_TYPE_BOOLEAN) {
1565 		fprintf (stderr,
1566 			 "%s %d : property '%s' for device '%s' is not "
1567 			 "of type bool\n", __FILE__, __LINE__, key, udi);
1568 		dbus_message_unref (message);
1569 		dbus_message_unref (reply);
1570 		return FALSE;
1571 	}
1572 	dbus_message_iter_get_basic (&reply_iter, &value);
1573 
1574 	dbus_message_unref (message);
1575 	dbus_message_unref (reply);
1576 	return value;
1577 }
1578 
1579 
1580 /* generic helper */
1581 static dbus_bool_t
1582 libhal_device_set_property_helper (LibHalContext *ctx,
1583 				   const char *udi,
1584 				   const char *key,
1585 				   int type,
1586 				   const char *str_value,
1587 				   dbus_int32_t int_value,
1588 				   dbus_uint64_t uint64_value,
1589 				   double double_value,
1590 				   dbus_bool_t bool_value,
1591 				   DBusError *error)
1592 {
1593 	DBusMessage *message;
1594 	DBusMessage *reply;
1595 	DBusMessageIter iter;
1596 	char *method_name = NULL;
1597 
1598 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
1599 
1600 	/** @todo  sanity check incoming params */
1601 	switch (type) {
1602 	case DBUS_TYPE_INVALID:
1603 		method_name = "RemoveProperty";
1604 		break;
1605 	case DBUS_TYPE_STRING:
1606 		method_name = "SetPropertyString";
1607 		break;
1608 	case DBUS_TYPE_INT32:
1609 	case DBUS_TYPE_UINT64:
1610 		method_name = "SetPropertyInteger";
1611 		break;
1612 	case DBUS_TYPE_DOUBLE:
1613 		method_name = "SetPropertyDouble";
1614 		break;
1615 	case DBUS_TYPE_BOOLEAN:
1616 		method_name = "SetPropertyBoolean";
1617 		break;
1618 
1619 	default:
1620 		/* cannot happen; is not callable from outside this file */
1621 		break;
1622 	}
1623 
1624 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
1625 						"org.freedesktop.Hal.Device",
1626 						method_name);
1627 	if (message == NULL) {
1628 		fprintf (stderr,
1629 			 "%s %d : Couldn't allocate D-BUS message\n",
1630 			 __FILE__, __LINE__);
1631 		return FALSE;
1632 	}
1633 
1634 	dbus_message_iter_init_append (message, &iter);
1635 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
1636 	switch (type) {
1637 	case DBUS_TYPE_STRING:
1638 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &str_value);
1639 		break;
1640 	case DBUS_TYPE_INT32:
1641 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &int_value);
1642 		break;
1643 	case DBUS_TYPE_UINT64:
1644 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT64, &uint64_value);
1645 		break;
1646 	case DBUS_TYPE_DOUBLE:
1647 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_DOUBLE, &double_value);
1648 		break;
1649 	case DBUS_TYPE_BOOLEAN:
1650 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &bool_value);
1651 		break;
1652 	}
1653 
1654 
1655 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
1656 							   message, -1,
1657 							   error);
1658 	if (dbus_error_is_set (error)) {
1659 		dbus_message_unref (message);
1660 		return FALSE;
1661 	}
1662 
1663 	if (reply == NULL) {
1664 		dbus_message_unref (message);
1665 		return FALSE;
1666 	}
1667 
1668 	dbus_message_unref (message);
1669 	dbus_message_unref (reply);
1670 
1671 	return TRUE;
1672 }
1673 
1674 /**
1675  * libhal_device_set_property_string:
1676  * @ctx: the context for the connection to hald
1677  * @udi: the Unique Device Id
1678  * @key: name of the property
1679  * @value: value of the property; a UTF8 string
1680  * @error: pointer to an initialized dbus error object for returning errors or NULL
1681  *
1682  * Set a property of type string.
1683  *
1684  * Returns: TRUE if the property was set, FALSE if the device didn't
1685  * exist or the property had a different type.
1686  */
1687 dbus_bool_t
1688 libhal_device_set_property_string (LibHalContext *ctx,
1689 				   const char *udi,
1690 				   const char *key,
1691 				   const char *value,
1692 				   DBusError *error)
1693 {
1694 	return libhal_device_set_property_helper (ctx, udi, key,
1695 						  DBUS_TYPE_STRING,
1696 						  value, 0, 0, 0.0f, FALSE, error);
1697 }
1698 
1699 /**
1700  * libhal_device_set_property_int:
1701  * @ctx: the context for the connection to hald
1702  * @udi: the Unique Device Id
1703  * @key: name of the property
1704  * @value: value of the property
1705  * @error: pointer to an initialized dbus error object for returning errors or NULL
1706  *
1707  * Set a property of type signed integer.
1708  *
1709  * Returns: TRUE if the property was set, FALSE if the device didn't
1710  * exist or the property had a different type.
1711  */
1712 dbus_bool_t
1713 libhal_device_set_property_int (LibHalContext *ctx, const char *udi,
1714 				const char *key, dbus_int32_t value, DBusError *error)
1715 {
1716 	return libhal_device_set_property_helper (ctx, udi, key,
1717 						  DBUS_TYPE_INT32,
1718 						  NULL, value, 0, 0.0f, FALSE, error);
1719 }
1720 
1721 /**
1722  * libhal_device_set_property_uint64:
1723  * @ctx: the context for the connection to hald
1724  * @udi: the Unique Device Id
1725  * @key: name of the property
1726  * @value: value of the property
1727  * @error: pointer to an initialized dbus error object for returning errors or NULL
1728  *
1729  * Set a property of type unsigned integer.
1730  *
1731  * Returns: TRUE if the property was set, FALSE if the device didn't
1732  * exist or the property had a different type.
1733  */
1734 dbus_bool_t
1735 libhal_device_set_property_uint64 (LibHalContext *ctx, const char *udi,
1736 				   const char *key, dbus_uint64_t value, DBusError *error)
1737 {
1738 	return libhal_device_set_property_helper (ctx, udi, key,
1739 						  DBUS_TYPE_UINT64,
1740 						  NULL, 0, value, 0.0f, FALSE, error);
1741 }
1742 
1743 /**
1744  * libhal_device_set_property_double:
1745  * @ctx: the context for the connection to hald
1746  * @udi: the Unique Device Id
1747  * @key: name of the property
1748  * @value: value of the property
1749  * @error: pointer to an initialized dbus error object for returning errors or NULL
1750  *
1751  * Set a property of type double.
1752  *
1753  * Returns: TRUE if the property was set, FALSE if the device didn't
1754  * exist or the property had a different type.
1755  */
1756 dbus_bool_t
1757 libhal_device_set_property_double (LibHalContext *ctx, const char *udi,
1758 				   const char *key, double value, DBusError *error)
1759 {
1760 	return libhal_device_set_property_helper (ctx, udi, key,
1761 						  DBUS_TYPE_DOUBLE,
1762 						  NULL, 0, 0, value, FALSE, error);
1763 }
1764 
1765 /**
1766  * libhal_device_set_property_bool:
1767  * @ctx: the context for the connection to hald
1768  * @udi: the Unique Device Id
1769  * @key: name of the property
1770  * @value: value of the property
1771  * @error: pointer to an initialized dbus error object for returning errors or NULL
1772  *
1773  * Set a property of type bool.
1774  *
1775  * Returns: TRUE if the property was set, FALSE if the device didn't
1776  * exist or the property had a different type.
1777  */
1778 dbus_bool_t
1779 libhal_device_set_property_bool (LibHalContext *ctx, const char *udi,
1780 				 const char *key, dbus_bool_t value, DBusError *error)
1781 {
1782 	return libhal_device_set_property_helper (ctx, udi, key,
1783 						  DBUS_TYPE_BOOLEAN,
1784 						  NULL, 0, 0, 0.0f, value, error);
1785 }
1786 
1787 
1788 /**
1789  * libhal_device_remove_property:
1790  * @ctx: the context for the connection to hald
1791  * @udi: the Unique Device Id
1792  * @key: name of the property
1793  * @error: pointer to an initialized dbus error object for returning errors or NULL
1794  *
1795  * Remove a property.
1796  *
1797  * Returns: TRUE if the property was set, FALSE if the device didn't
1798  * exist
1799  */
1800 dbus_bool_t
1801 libhal_device_remove_property (LibHalContext *ctx,
1802 			       const char *udi, const char *key, DBusError *error)
1803 {
1804 	return libhal_device_set_property_helper (ctx, udi, key, DBUS_TYPE_INVALID,
1805 						  /* DBUS_TYPE_INVALID means remove */
1806 						  NULL, 0, 0, 0.0f, FALSE, error);
1807 }
1808 
1809 /**
1810  * libhal_device_property_strlist_append:
1811  * @ctx: the context for the connection to hald
1812  * @udi: the Unique Device Id
1813  * @key: name of the property
1814  * @value: value to append to property
1815  * @error: pointer to an initialized dbus error object for returning errors or NULL
1816  *
1817  * Append to a property of type strlist.
1818  *
1819  * Returns: TRUE if the value was appended, FALSE if the device didn't
1820  * exist or the property had a different type.
1821  */
1822 dbus_bool_t
1823 libhal_device_property_strlist_append (LibHalContext *ctx,
1824 				       const char *udi,
1825 				       const char *key,
1826 				       const char *value,
1827 				       DBusError *error)
1828 {
1829 	DBusMessage *message;
1830 	DBusMessage *reply;
1831 	DBusMessageIter iter;
1832 
1833 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
1834 
1835 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
1836 						"org.freedesktop.Hal.Device",
1837 						"StringListAppend");
1838 	if (message == NULL) {
1839 		fprintf (stderr,
1840 			 "%s %d : Couldn't allocate D-BUS message\n",
1841 			 __FILE__, __LINE__);
1842 		return FALSE;
1843 	}
1844 	dbus_message_iter_init_append (message, &iter);
1845 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
1846 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value);
1847 
1848 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
1849 							   message, -1,
1850 							   error);
1851 	if (dbus_error_is_set (error)) {
1852 		dbus_message_unref (message);
1853 		return FALSE;
1854 	}
1855 	if (reply == NULL) {
1856 		dbus_message_unref (message);
1857 		return FALSE;
1858 	}
1859 	return TRUE;
1860 }
1861 
1862 /**
1863  * libhal_device_property_strlist_prepend:
1864  * @ctx: the context for the connection to hald
1865  * @udi: the Unique Device Id
1866  * @key: name of the property
1867  * @value: value to prepend to property
1868  * @error: pointer to an initialized dbus error object for returning errors or NULL
1869  *
1870  * Prepend to a property of type strlist.
1871  *
1872  * Returns: TRUE if the value was prepended, FALSE if the device
1873  * didn't exist or the property had a different type.
1874  */
1875 dbus_bool_t
1876 libhal_device_property_strlist_prepend (LibHalContext *ctx,
1877 					const char *udi,
1878 					const char *key,
1879 					const char *value,
1880 					DBusError *error)
1881 {
1882 	DBusMessage *message;
1883 	DBusMessage *reply;
1884 	DBusMessageIter iter;
1885 
1886 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
1887 
1888 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
1889 						"org.freedesktop.Hal.Device",
1890 						"StringListPrepend");
1891 	if (message == NULL) {
1892 		fprintf (stderr,
1893 			 "%s %d : Couldn't allocate D-BUS message\n",
1894 			 __FILE__, __LINE__);
1895 		return FALSE;
1896 	}
1897 	dbus_message_iter_init_append (message, &iter);
1898 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
1899 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value);
1900 
1901 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
1902 							   message, -1,
1903 							   error);
1904 	if (dbus_error_is_set (error)) {
1905 		dbus_message_unref (message);
1906 		return FALSE;
1907 	}
1908 	if (reply == NULL) {
1909 		dbus_message_unref (message);
1910 		return FALSE;
1911 	}
1912 	return TRUE;
1913 }
1914 
1915 /**
1916  * libhal_device_property_strlist_remove_index:
1917  * @ctx: the context for the connection to hald
1918  * @udi: the Unique Device Id
1919  * @key: name of the property
1920  * @idx: index of string to remove in the strlist
1921  * @error: pointer to an initialized dbus error object for returning errors or NULL
1922  *
1923  * Remove a specified string from a property of type strlist.
1924  *
1925  * Returns: TRUE if the string was removed, FALSE if the device didn't
1926  * exist or the property had a different type.
1927  */
1928 dbus_bool_t
1929 libhal_device_property_strlist_remove_index (LibHalContext *ctx,
1930 					     const char *udi,
1931 					     const char *key,
1932 					     unsigned int idx,
1933 					     DBusError *error)
1934 {
1935 	DBusMessage *message;
1936 	DBusMessage *reply;
1937 	DBusMessageIter iter;
1938 
1939 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
1940 
1941 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
1942 						"org.freedesktop.Hal.Device",
1943 						"StringListRemoveIndex");
1944 	if (message == NULL) {
1945 		fprintf (stderr,
1946 			 "%s %d : Couldn't allocate D-BUS message\n",
1947 			 __FILE__, __LINE__);
1948 		return FALSE;
1949 	}
1950 	dbus_message_iter_init_append (message, &iter);
1951 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
1952 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &idx);
1953 
1954 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
1955 							   message, -1,
1956 							   error);
1957 	if (dbus_error_is_set (error)) {
1958 		dbus_message_unref (message);
1959 		return FALSE;
1960 	}
1961 	if (reply == NULL) {
1962 		dbus_message_unref (message);
1963 		return FALSE;
1964 	}
1965 	return TRUE;
1966 }
1967 
1968 /**
1969  * libhal_device_property_strlist_remove:
1970  * @ctx: the context for the connection to hald
1971  * @udi: the Unique Device Id
1972  * @key: name of the property
1973  * @value: the string to remove
1974  * @error: pointer to an initialized dbus error object for returning errors or NULL
1975  *
1976  * Remove a specified string from a property of type strlist.
1977  *
1978  * Returns: TRUE if the string was removed, FALSE if the device didn't
1979  * exist or the property had a different type.
1980  */
1981 dbus_bool_t
1982 libhal_device_property_strlist_remove (LibHalContext *ctx,
1983 				       const char *udi,
1984 				       const char *key,
1985 				       const char *value, DBusError *error)
1986 {
1987 	DBusMessage *message;
1988 	DBusMessage *reply;
1989 	DBusMessageIter iter;
1990 
1991 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
1992 
1993 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
1994 						"org.freedesktop.Hal.Device",
1995 						"StringListRemove");
1996 	if (message == NULL) {
1997 		fprintf (stderr,
1998 			 "%s %d : Couldn't allocate D-BUS message\n",
1999 			 __FILE__, __LINE__);
2000 		return FALSE;
2001 	}
2002 	dbus_message_iter_init_append (message, &iter);
2003 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
2004 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value);
2005 
2006 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
2007 							   message, -1,
2008 							   error);
2009 	if (dbus_error_is_set (error)) {
2010 		dbus_message_unref (message);
2011 		return FALSE;
2012 	}
2013 	if (reply == NULL) {
2014 		dbus_message_unref (message);
2015 		return FALSE;
2016 	}
2017 	return TRUE;
2018 }
2019 
2020 
2021 /**
2022  * libhal_device_lock:
2023  * @ctx: the context for the connection to hald
2024  * @udi: the Unique Device Id
2025  * @reason_to_lock: a user-presentable reason why the device is locked.
2026  * @reason_why_locked: a pointer to store the reason why the device cannot be locked on failure, or NULL
2027  * @error: pointer to an initialized dbus error object for returning errors or NULL
2028  *
2029  * Take an advisory lock on the device.
2030  *
2031  * Returns: TRUE if the lock was obtained, FALSE otherwise
2032  */
2033 dbus_bool_t
2034 libhal_device_lock (LibHalContext *ctx,
2035 		    const char *udi,
2036 		    const char *reason_to_lock,
2037 		    char **reason_why_locked, DBusError *error)
2038 {
2039 	DBusMessage *message;
2040 	DBusMessageIter iter;
2041 	DBusMessage *reply;
2042 
2043 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
2044 
2045 	if (reason_why_locked != NULL)
2046 		*reason_why_locked = NULL;
2047 
2048 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
2049 						udi,
2050 						"org.freedesktop.Hal.Device",
2051 						"Lock");
2052 
2053 	if (message == NULL) {
2054 		fprintf (stderr,
2055 			 "%s %d : Couldn't allocate D-BUS message\n",
2056 			 __FILE__, __LINE__);
2057 		return FALSE;
2058 	}
2059 
2060 	dbus_message_iter_init_append (message, &iter);
2061 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &reason_to_lock);
2062 
2063 
2064 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
2065 							   message, -1,
2066 							   error);
2067 
2068 	if (dbus_error_is_set (error)) {
2069 		if (strcmp (error->name,
2070 			    "org.freedesktop.Hal.DeviceAlreadyLocked") == 0) {
2071 			if (reason_why_locked != NULL) {
2072 				*reason_why_locked =
2073 					dbus_malloc0 (strlen (error->message) + 1);
2074 				strcpy (*reason_why_locked, error->message);
2075 			}
2076 		}
2077 
2078 		dbus_message_unref (message);
2079 		return FALSE;
2080 	}
2081 
2082 	dbus_message_unref (message);
2083 
2084 	if (reply == NULL)
2085 		return FALSE;
2086 
2087 	dbus_message_unref (reply);
2088 
2089 	return TRUE;
2090 }
2091 
2092 /**
2093  * libhal_device_unlock:
2094  * @ctx: the context for the connection to hald
2095  * @udi: the Unique Device Id
2096  * @error: pointer to an initialized dbus error object for returning errors or NULL
2097  *
2098  * Release an advisory lock on the device.
2099  *
2100  * Returns: TRUE if the device was successfully unlocked,
2101  *                              FALSE otherwise
2102  */
2103 dbus_bool_t
2104 libhal_device_unlock (LibHalContext *ctx,
2105 		      const char *udi, DBusError *error)
2106 {
2107 	DBusMessage *message;
2108 	DBusMessage *reply;
2109 
2110 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
2111 
2112 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
2113 						udi,
2114 						"org.freedesktop.Hal.Device",
2115 						"Unlock");
2116 
2117 	if (message == NULL) {
2118 		fprintf (stderr,
2119 			 "%s %d : Couldn't allocate D-BUS message\n",
2120 			 __FILE__, __LINE__);
2121 		return FALSE;
2122 	}
2123 
2124 
2125 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
2126 							   message, -1,
2127 							   error);
2128 
2129 	if (dbus_error_is_set (error)) {
2130 		dbus_message_unref (message);
2131 		return FALSE;
2132 	}
2133 
2134 	dbus_message_unref (message);
2135 
2136 	if (reply == NULL)
2137 		return FALSE;
2138 
2139 	dbus_message_unref (reply);
2140 
2141 	return TRUE;
2142 }
2143 
2144 
2145 /**
2146  * libhal_new_device:
2147  * @ctx: the context for the connection to hald
2148  * @error: pointer to an initialized dbus error object for returning errors or NULL
2149  *
2150  * Create a new device object which will be hidden from applications
2151  * until the CommitToGdl(), ie. libhal_device_commit_to_gdl(), method
2152  * is called. Note that the program invoking this method needs to run
2153  * with super user privileges.
2154  *
2155  * Returns: Temporary device unique id or NULL if there was a
2156  * problem. This string must be freed by the caller.
2157  */
2158 char *
2159 libhal_new_device (LibHalContext *ctx, DBusError *error)
2160 {
2161 	DBusMessage *message;
2162 	DBusMessage *reply;
2163 	DBusMessageIter reply_iter;
2164 	char *value;
2165 	char *dbus_str;
2166 
2167 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
2168 
2169 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
2170 						"/org/freedesktop/Hal/Manager",
2171 						"org.freedesktop.Hal.Manager",
2172 						"NewDevice");
2173 	if (message == NULL) {
2174 		fprintf (stderr,
2175 			 "%s %d : Couldn't allocate D-BUS message\n",
2176 			 __FILE__, __LINE__);
2177 		return NULL;
2178 	}
2179 
2180 
2181 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
2182 							   message, -1,
2183 							   error);
2184 	if (dbus_error_is_set (error)) {
2185 		dbus_message_unref (message);
2186 		return NULL;
2187 	}
2188 	if (reply == NULL) {
2189 		dbus_message_unref (message);
2190 		return NULL;
2191 	}
2192 
2193 	dbus_message_iter_init (reply, &reply_iter);
2194 
2195 	/* now analyze reply */
2196 	if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_STRING) {
2197 		fprintf (stderr,
2198 			 "%s %d : expected a string in reply to NewDevice\n",
2199 			 __FILE__, __LINE__);
2200 		dbus_message_unref (message);
2201 		dbus_message_unref (reply);
2202 		return NULL;
2203 	}
2204 
2205 	dbus_message_iter_get_basic (&reply_iter, &dbus_str);
2206 	value = (char *) ((dbus_str != NULL) ? strdup (dbus_str) : NULL);
2207 	if (value == NULL) {
2208 		fprintf (stderr, "%s %d : error allocating memory\n",
2209 			 __FILE__, __LINE__);
2210 	}
2211 
2212 	dbus_message_unref (message);
2213 	dbus_message_unref (reply);
2214 	return value;
2215 }
2216 
2217 
2218 /**
2219  * libhal_device_commit_to_gdl:
2220  * @ctx: the context for the connection to hald
2221  * @temp_udi: the temporary unique device id as returned by libhal_new_device()
2222  * @udi: the new unique device id.
2223  * @error: pointer to an initialized dbus error object for returning errors or NULL
2224  *
2225  * When a hidden device has been built using the NewDevice method,
2226  * ie. libhal_new_device(), and the org.freedesktop.Hal.Device
2227  * interface this function will commit it to the global device list.
2228  *
2229  * This means that the device object will be visible to applications
2230  * and the HAL daemon will possibly attempt to boot the device
2231  * (depending on the property RequireEnable).
2232  *
2233  * Note that the program invoking this method needs to run with super
2234  * user privileges.
2235  *
2236  * Returns: FALSE if the given unique device id is already in use.
2237  */
2238 dbus_bool_t
2239 libhal_device_commit_to_gdl (LibHalContext *ctx,
2240 			     const char *temp_udi, const char *udi, DBusError *error)
2241 {
2242 	DBusMessage *message;
2243 	DBusMessage *reply;
2244 	DBusMessageIter iter;
2245 
2246 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
2247 
2248 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
2249 						"/org/freedesktop/Hal/Manager",
2250 						"org.freedesktop.Hal.Manager",
2251 						"CommitToGdl");
2252 	if (message == NULL) {
2253 		fprintf (stderr,
2254 			 "%s %d : Couldn't allocate D-BUS message\n",
2255 			 __FILE__, __LINE__);
2256 		return FALSE;
2257 	}
2258 
2259 	dbus_message_iter_init_append (message, &iter);
2260 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &temp_udi);
2261 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
2262 
2263 
2264 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
2265 							   message, -1,
2266 							   error);
2267 	if (dbus_error_is_set (error)) {
2268 		dbus_message_unref (message);
2269 		return FALSE;
2270 	}
2271 	if (reply == NULL) {
2272 		dbus_message_unref (message);
2273 		return FALSE;
2274 	}
2275 
2276 	dbus_message_unref (message);
2277 	dbus_message_unref (reply);
2278 	return TRUE;
2279 }
2280 
2281 /**
2282  * libhal_remove_device:
2283  * @ctx: the context for the connection to hald
2284  * @udi: the Unique device id.
2285  * @error: pointer to an initialized dbus error object for returning errors or NULL
2286  *
2287  * This method can be invoked when a device is removed. The HAL daemon
2288  * will shut down the device. Note that the device may still be in the
2289  * device list if the Persistent property is set to true.
2290  *
2291  * Note that the program invoking this method needs to run with super
2292  * user privileges.
2293  *
2294  * Returns: TRUE if the device was removed, FALSE otherwise
2295  */
2296 dbus_bool_t
2297 libhal_remove_device (LibHalContext *ctx, const char *udi, DBusError *error)
2298 {
2299 	DBusMessage *message;
2300 	DBusMessage *reply;
2301 	DBusMessageIter iter;
2302 
2303 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
2304 
2305 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
2306 						"/org/freedesktop/Hal/Manager",
2307 						"org.freedesktop.Hal.Manager",
2308 						"Remove");
2309 	if (message == NULL) {
2310 		fprintf (stderr,
2311 			 "%s %d : Couldn't allocate D-BUS message\n",
2312 			 __FILE__, __LINE__);
2313 		return FALSE;
2314 	}
2315 
2316 	dbus_message_iter_init_append (message, &iter);
2317 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
2318 
2319 
2320 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
2321 							   message, -1,
2322 							   error);
2323 	if (dbus_error_is_set (error)) {
2324 		dbus_message_unref (message);
2325 		return FALSE;
2326 	}
2327 	if (reply == NULL) {
2328 		dbus_message_unref (message);
2329 		return FALSE;
2330 	}
2331 
2332 	dbus_message_unref (message);
2333 	dbus_message_unref (reply);
2334 	return TRUE;
2335 }
2336 
2337 /**
2338  * libhal_device_exists:
2339  * @ctx: the context for the connection to hald
2340  * @udi: the Unique device id.
2341  * @error: pointer to an initialized dbus error object for returning errors or NULL
2342  *
2343  * Determine if a device exists.
2344  *
2345  * Returns: TRUE if the device exists
2346  */
2347 dbus_bool_t
2348 libhal_device_exists (LibHalContext *ctx, const char *udi, DBusError *error)
2349 {
2350 	DBusMessage *message;
2351 	DBusMessage *reply;
2352 	DBusMessageIter iter, reply_iter;
2353 	dbus_bool_t value;
2354 	DBusError _error;
2355 
2356 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
2357 
2358 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
2359 						"/org/freedesktop/Hal/Manager",
2360 						"org.freedesktop.Hal.Manager",
2361 						"DeviceExists");
2362 	if (message == NULL) {
2363 		fprintf (stderr,
2364 			 "%s %d : Couldn't allocate D-BUS message\n",
2365 			 __FILE__, __LINE__);
2366 		return FALSE;
2367 	}
2368 
2369 	dbus_message_iter_init_append (message, &iter);
2370 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
2371 
2372 	dbus_error_init (&_error);
2373 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
2374 							   message, -1,
2375 							   &_error);
2376 
2377 	dbus_move_error (&_error, error);
2378 	if (error != NULL && dbus_error_is_set (error)) {
2379 		dbus_message_unref (message);
2380 		return FALSE;
2381 	}
2382 	if (reply == NULL) {
2383 		dbus_message_unref (message);
2384 		return FALSE;
2385 	}
2386 
2387 	dbus_message_iter_init (reply, &reply_iter);
2388 
2389 	/* now analyze reply */
2390 	if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) {
2391 		fprintf (stderr,
2392 			 "%s %d : expected a bool in reply to DeviceExists\n",
2393 			 __FILE__, __LINE__);
2394 		dbus_message_unref (message);
2395 		dbus_message_unref (reply);
2396 		return FALSE;
2397 	}
2398 
2399 	dbus_message_iter_get_basic (&reply_iter, &value);
2400 
2401 	dbus_message_unref (message);
2402 	dbus_message_unref (reply);
2403 	return value;
2404 }
2405 
2406 /**
2407  * libhal_device_property_exists:
2408  * @ctx: the context for the connection to hald
2409  * @udi: the Unique device id.
2410  * @key: name of the property
2411  * @error: pointer to an initialized dbus error object for returning errors or NULL
2412  *
2413  * Determine if a property on a device exists.
2414  *
2415  * Returns: TRUE if the device exists, FALSE otherwise
2416  */
2417 dbus_bool_t
2418 libhal_device_property_exists (LibHalContext *ctx,
2419 			       const char *udi, const char *key, DBusError *error)
2420 {
2421 	DBusMessage *message;
2422 	DBusMessage *reply;
2423 	DBusMessageIter iter, reply_iter;
2424 	dbus_bool_t value;
2425 	DBusError _error;
2426 
2427 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
2428 
2429 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
2430 						"org.freedesktop.Hal.Device",
2431 						"PropertyExists");
2432 	if (message == NULL) {
2433 		fprintf (stderr,
2434 			 "%s %d : Couldn't allocate D-BUS message\n",
2435 			 __FILE__, __LINE__);
2436 		return FALSE;
2437 	}
2438 
2439 	dbus_message_iter_init_append (message, &iter);
2440 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
2441 
2442 	dbus_error_init (&_error);
2443 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
2444 							   message, -1,
2445 							   &_error);
2446 
2447 	dbus_move_error (&_error, error);
2448 	if (error != NULL && dbus_error_is_set (error)) {
2449 		dbus_message_unref (message);
2450 		return FALSE;
2451 	}
2452 	if (reply == NULL) {
2453 		dbus_message_unref (message);
2454 		return FALSE;
2455 	}
2456 
2457 	dbus_message_iter_init (reply, &reply_iter);
2458 
2459 	/* now analyse reply */
2460 	if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) {
2461 		fprintf (stderr, "%s %d : expected a bool in reply to "
2462 			 "PropertyExists\n", __FILE__, __LINE__);
2463 		dbus_message_unref (message);
2464 		dbus_message_unref (reply);
2465 		return FALSE;
2466 	}
2467 
2468 	dbus_message_iter_get_basic (&reply_iter, &value);
2469 
2470 	dbus_message_unref (message);
2471 	dbus_message_unref (reply);
2472 	return value;
2473 }
2474 
2475 /**
2476  * libhal_merge_properties:
2477  * @ctx: the context for the connection to hald
2478  * @target_udi: the Unique device id of target device to merge to
2479  * @source_udi: the Unique device id of device to merge from
2480  * @error: pointer to an initialized dbus error object for returning errors or NULL
2481  *
2482  * Merge properties from one device to another.
2483  *
2484  * Returns: TRUE if the properties were merged, FALSE otherwise
2485  */
2486 dbus_bool_t
2487 libhal_merge_properties (LibHalContext *ctx,
2488 			 const char *target_udi, const char *source_udi, DBusError *error)
2489 {
2490 	DBusMessage *message;
2491 	DBusMessage *reply;
2492 	DBusMessageIter iter;
2493 
2494 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
2495 
2496 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
2497 						"/org/freedesktop/Hal/Manager",
2498 						"org.freedesktop.Hal.Manager",
2499 						"MergeProperties");
2500 	if (message == NULL) {
2501 		fprintf (stderr,
2502 			 "%s %d : Couldn't allocate D-BUS message\n",
2503 			 __FILE__, __LINE__);
2504 		return FALSE;
2505 	}
2506 
2507 	dbus_message_iter_init_append (message, &iter);
2508 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &target_udi);
2509 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &source_udi);
2510 
2511 
2512 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
2513 							   message, -1,
2514 							   error);
2515 	if (dbus_error_is_set (error)) {
2516 		dbus_message_unref (message);
2517 		return FALSE;
2518 	}
2519 	if (reply == NULL) {
2520 		dbus_message_unref (message);
2521 		return FALSE;
2522 	}
2523 
2524 	dbus_message_unref (message);
2525 	dbus_message_unref (reply);
2526 	return TRUE;
2527 }
2528 
2529 /**
2530  * libhal_device_matches:
2531  * @ctx: the context for the connection to hald
2532  * @udi1: the Unique Device Id for device 1
2533  * @udi2: the Unique Device Id for device 2
2534  * @property_namespace: the namespace for set of devices, e.g. "usb"
2535  * @error: pointer to an initialized dbus error object for returning errors or NULL
2536  *
2537  * Check a set of properties for two devices matches.
2538  *
2539  * Checks that all properties where keys, starting with a given value
2540  * (namespace), of the first device is in the second device and that
2541  * they got the same value and type.
2542  *
2543  * Note that the other inclusion isn't tested, so there could be
2544  * properties (from the given namespace) in the second device not
2545  * present in the first device.
2546  *
2547  * Returns: TRUE if all properties starting with the given namespace
2548  * parameter from one device is in the other and have the same value.
2549  */
2550 dbus_bool_t
2551 libhal_device_matches (LibHalContext *ctx,
2552 		       const char *udi1, const char *udi2,
2553 		       const char *property_namespace, DBusError *error)
2554 {
2555 	DBusMessage *message;
2556 	DBusMessage *reply;
2557 	DBusMessageIter iter, reply_iter;
2558 	dbus_bool_t value;
2559 	DBusError _error;
2560 
2561 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
2562 
2563 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
2564 						"/org/freedesktop/Hal/Manager",
2565 						"org.freedesktop.Hal.Manager",
2566 						"DeviceMatches");
2567 	if (message == NULL) {
2568 		fprintf (stderr,
2569 			 "%s %d : Couldn't allocate D-BUS message\n",
2570 			 __FILE__, __LINE__);
2571 		return FALSE;
2572 	}
2573 
2574 	dbus_message_iter_init_append (message, &iter);
2575 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, udi1);
2576 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, udi2);
2577 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, property_namespace);
2578 
2579 	dbus_error_init (&_error);
2580 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
2581 							   message, -1,
2582 							   &_error);
2583 
2584 	dbus_move_error (&_error, error);
2585 	if (error != NULL && dbus_error_is_set (error)) {
2586 		dbus_message_unref (message);
2587 		return FALSE;
2588 	}
2589 	if (reply == NULL) {
2590 		dbus_message_unref (message);
2591 		return FALSE;
2592 	}
2593 	/* now analyse reply */
2594 	dbus_message_iter_init (reply, &reply_iter);
2595 
2596 	if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) {
2597 		fprintf (stderr,
2598 			 "%s %d : expected a bool in reply to DeviceMatches\n",
2599 			 __FILE__, __LINE__);
2600 		dbus_message_unref (message);
2601 		dbus_message_unref (reply);
2602 		return FALSE;
2603 	}
2604 
2605 	dbus_message_iter_get_basic (&reply_iter, &value);
2606 
2607 	dbus_message_unref (message);
2608 	dbus_message_unref (reply);
2609 	return value;
2610 }
2611 
2612 /**
2613  * libhal_device_print:
2614  * @ctx: the context for the connection to hald
2615  * @udi: the Unique Device Id
2616  * @error: pointer to an initialized dbus error object for returning errors or NULL
2617  *
2618  * Print a device to stdout; useful for debugging.
2619  *
2620  * Returns: TRUE if device's information could be obtained, FALSE otherwise
2621  */
2622 dbus_bool_t
2623 libhal_device_print (LibHalContext *ctx, const char *udi, DBusError *error)
2624 {
2625 	int type;
2626 	char *key;
2627 	LibHalPropertySet *pset;
2628 	LibHalPropertySetIterator i;
2629 
2630 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
2631 
2632 	printf ("device_id = %s\n", udi);
2633 
2634 	if ((pset = libhal_device_get_all_properties (ctx, udi, error)) == NULL)
2635 		return FALSE;
2636 
2637 	for (libhal_psi_init (&i, pset); libhal_psi_has_more (&i);
2638 	     libhal_psi_next (&i)) {
2639 		type = libhal_psi_get_type (&i);
2640 		key = libhal_psi_get_key (&i);
2641 
2642 		switch (type) {
2643 		case LIBHAL_PROPERTY_TYPE_STRING:
2644 			printf ("    %s = '%s' (string)\n", key,
2645 				libhal_psi_get_string (&i));
2646 			break;
2647 		case LIBHAL_PROPERTY_TYPE_INT32:
2648 			printf ("    %s = %d = 0x%x (int)\n", key,
2649 				libhal_psi_get_int (&i),
2650 				libhal_psi_get_int (&i));
2651 			break;
2652 		case LIBHAL_PROPERTY_TYPE_UINT64:
2653 			printf ("    %s = %llu = 0x%llx (uint64)\n", key,
2654 				(long long unsigned int) libhal_psi_get_uint64 (&i),
2655 				(long long unsigned int) libhal_psi_get_uint64 (&i));
2656 			break;
2657 		case LIBHAL_PROPERTY_TYPE_BOOLEAN:
2658 			printf ("    %s = %s (bool)\n", key,
2659 				(libhal_psi_get_bool (&i) ? "true" :
2660 				 "false"));
2661 			break;
2662 		case LIBHAL_PROPERTY_TYPE_DOUBLE:
2663 			printf ("    %s = %g (double)\n", key,
2664 				libhal_psi_get_double (&i));
2665 			break;
2666 		case LIBHAL_PROPERTY_TYPE_STRLIST:
2667 		{
2668 			unsigned int j;
2669 			char **str_list;
2670 
2671 			str_list = libhal_psi_get_strlist (&i);
2672 			printf ("    %s = [", key);
2673 			for (j = 0; str_list[j] != NULL; j++) {
2674 				printf ("'%s'", str_list[j]);
2675 				if (str_list[j+1] != NULL)
2676 					printf (", ");
2677 			}
2678 			printf ("] (string list)\n");
2679 
2680 			break;
2681 		}
2682 		default:
2683 			printf ("    *** unknown type for key %s\n", key);
2684 			break;
2685 		}
2686 	}
2687 
2688 	libhal_free_property_set (pset);
2689 
2690 	return TRUE;
2691 }
2692 
2693 /**
2694  * libhal_manager_find_device_string_match:
2695  * @ctx: the context for the connection to hald
2696  * @key: name of the property
2697  * @value: the value to match
2698  * @num_devices: pointer to store number of devices
2699  * @error: pointer to an initialized dbus error object for returning errors or NULL
2700  *
2701  * Find a device in the GDL where a single string property matches a
2702  * given value.
2703  *
2704  * Returns: UDI of devices; free with libhal_free_string_array()
2705  */
2706 char **
2707 libhal_manager_find_device_string_match (LibHalContext *ctx,
2708 					 const char *key,
2709 					 const char *value, int *num_devices, DBusError *error)
2710 {
2711 	DBusMessage *message;
2712 	DBusMessage *reply;
2713 	DBusMessageIter iter, iter_array, reply_iter;
2714 	char **hal_device_names;
2715 	DBusError _error;
2716 
2717 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
2718 
2719 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
2720 						"/org/freedesktop/Hal/Manager",
2721 						"org.freedesktop.Hal.Manager",
2722 						"FindDeviceStringMatch");
2723 	if (message == NULL) {
2724 		fprintf (stderr,
2725 			 "%s %d : Couldn't allocate D-BUS message\n",
2726 			 __FILE__, __LINE__);
2727 		return NULL;
2728 	}
2729 
2730 	dbus_message_iter_init_append (message, &iter);
2731 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
2732 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value);
2733 
2734 	dbus_error_init (&_error);
2735 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
2736 							   message, -1,
2737 							   &_error);
2738 
2739 	dbus_move_error (&_error, error);
2740 	if (error != NULL && dbus_error_is_set (error)) {
2741 		dbus_message_unref (message);
2742 		return NULL;
2743 	}
2744 	if (reply == NULL) {
2745 		dbus_message_unref (message);
2746 		return NULL;
2747 	}
2748 	/* now analyse reply */
2749 	dbus_message_iter_init (reply, &reply_iter);
2750 
2751 	if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) {
2752 		fprintf (stderr, "%s %d : wrong reply from hald.  Expecting an array.\n", __FILE__, __LINE__);
2753 		return NULL;
2754 	}
2755 
2756 	dbus_message_iter_recurse (&reply_iter, &iter_array);
2757 
2758 	hal_device_names = libhal_get_string_array_from_iter (&iter_array, num_devices);
2759 
2760 	dbus_message_unref (reply);
2761 	dbus_message_unref (message);
2762 
2763 	return hal_device_names;
2764 }
2765 
2766 
2767 /**
2768  * libhal_device_add_capability:
2769  * @ctx: the context for the connection to hald
2770  * @udi: the Unique Device Id
2771  * @capability: the capability name to add
2772  * @error: pointer to an initialized dbus error object for returning errors or NULL
2773  *
2774  * Assign a capability to a device.
2775  *
2776  * Returns: TRUE if the capability was added, FALSE if the device didn't exist
2777  */
2778 dbus_bool_t
2779 libhal_device_add_capability (LibHalContext *ctx,
2780 			      const char *udi, const char *capability, DBusError *error)
2781 {
2782 	DBusMessage *message;
2783 	DBusMessage *reply;
2784 	DBusMessageIter iter;
2785 
2786 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
2787 
2788 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
2789 						"org.freedesktop.Hal.Device",
2790 						"AddCapability");
2791 	if (message == NULL) {
2792 		fprintf (stderr,
2793 			 "%s %d : Couldn't allocate D-BUS message\n",
2794 			 __FILE__, __LINE__);
2795 		return FALSE;
2796 	}
2797 
2798 	dbus_message_iter_init_append (message, &iter);
2799 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &capability);
2800 
2801 
2802 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
2803 							   message, -1,
2804 							   error);
2805 	if (dbus_error_is_set (error)) {
2806 		dbus_message_unref (message);
2807 		return FALSE;
2808 	}
2809 
2810 	if (reply == NULL) {
2811 		dbus_message_unref (message);
2812 		return FALSE;
2813 	}
2814 
2815 	dbus_message_unref (reply);
2816 	dbus_message_unref (message);
2817 	return TRUE;
2818 }
2819 
2820 /**
2821  * libhal_device_query_capability:
2822  * @ctx: the context for the connection to hald
2823  * @udi: the Unique Device Id
2824  * @capability: the capability name
2825  * @error: pointer to an initialized dbus error object for returning errors or NULL
2826  *
2827  * Check if a device has a capability. The result is undefined if the
2828  * device doesn't exist.
2829  *
2830  * Returns: TRUE if the device has the capability, otherwise FALSE
2831  */
2832 dbus_bool_t
2833 libhal_device_query_capability (LibHalContext *ctx, const char *udi, const char *capability, DBusError *error)
2834 {
2835 	char **caps;
2836 	unsigned int i;
2837 	dbus_bool_t ret;
2838 
2839 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
2840 
2841 	ret = FALSE;
2842 
2843 	caps = libhal_device_get_property_strlist (ctx, udi, "info.capabilities", error);
2844 	if (caps != NULL) {
2845 		for (i = 0; caps[i] != NULL; i++) {
2846 			if (strcmp (caps[i], capability) == 0) {
2847 				ret = TRUE;
2848 				break;
2849 			}
2850 		}
2851 		libhal_free_string_array (caps);
2852 	}
2853 
2854 	return ret;
2855 }
2856 
2857 /**
2858  * libhal_find_device_by_capability:
2859  * @ctx: the context for the connection to hald
2860  * @capability: the capability name
2861  * @num_devices: pointer to store number of devices
2862  * @error: pointer to an initialized dbus error object for returning errors or NULL
2863  *
2864  * Find devices with a given capability.
2865  *
2866  * Returns: UDI of devices; free with libhal_free_string_array()
2867  */
2868 char **
2869 libhal_find_device_by_capability (LibHalContext *ctx,
2870 				  const char *capability, int *num_devices, DBusError *error)
2871 {
2872 	DBusMessage *message;
2873 	DBusMessage *reply;
2874 	DBusMessageIter iter, iter_array, reply_iter;
2875 	char **hal_device_names;
2876 	DBusError _error;
2877 
2878 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
2879 
2880 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
2881 						"/org/freedesktop/Hal/Manager",
2882 						"org.freedesktop.Hal.Manager",
2883 						"FindDeviceByCapability");
2884 	if (message == NULL) {
2885 		fprintf (stderr,
2886 			 "%s %d : Couldn't allocate D-BUS message\n",
2887 			 __FILE__, __LINE__);
2888 		return NULL;
2889 	}
2890 
2891 	dbus_message_iter_init_append (message, &iter);
2892 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &capability);
2893 
2894 	dbus_error_init (&_error);
2895 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
2896 							   message, -1,
2897 							   &_error);
2898 
2899 	dbus_move_error (&_error, error);
2900 	if (error != NULL && dbus_error_is_set (error)) {
2901 		dbus_message_unref (message);
2902 		return NULL;
2903 	}
2904 	if (reply == NULL) {
2905 		dbus_message_unref (message);
2906 		return NULL;
2907 	}
2908 	/* now analyse reply */
2909 	dbus_message_iter_init (reply, &reply_iter);
2910 
2911 	if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) {
2912 		fprintf (stderr, "%s %d : wrong reply from hald.  Expecting an array.\n", __FILE__, __LINE__);
2913 		return NULL;
2914 	}
2915 
2916 	dbus_message_iter_recurse (&reply_iter, &iter_array);
2917 
2918 	hal_device_names = libhal_get_string_array_from_iter (&iter_array, num_devices);
2919 
2920 	dbus_message_unref (reply);
2921 	dbus_message_unref (message);
2922 
2923 	return hal_device_names;
2924 }
2925 
2926 /**
2927  * libhal_device_property_watch_all:
2928  * @ctx: the context for the connection to hald
2929  * @error: pointer to an initialized dbus error object for returning errors or NULL
2930  *
2931  * Watch all devices, ie. the device_property_changed callback is
2932  * invoked when the properties on any device changes.
2933  *
2934  * Returns: TRUE only if the operation succeeded
2935  */
2936 dbus_bool_t
2937 libhal_device_property_watch_all (LibHalContext *ctx, DBusError *error)
2938 {
2939 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
2940 
2941 	dbus_bus_add_match (ctx->connection,
2942 			    "type='signal',"
2943 			    "interface='org.freedesktop.Hal.Device',"
2944 			    "sender='org.freedesktop.Hal'", error);
2945 	if (dbus_error_is_set (error)) {
2946 		return FALSE;
2947 	}
2948 	return TRUE;
2949 }
2950 
2951 
2952 /**
2953  * libhal_device_add_property_watch:
2954  * @ctx: the context for the connection to hald
2955  * @udi: the Unique Device Id
2956  * @error: pointer to an initialized dbus error object for returning errors or NULL
2957  *
2958  * Add a watch on a device, so the device_property_changed callback is
2959  * invoked when the properties on the given device changes.
2960  *
2961  * The application itself is responsible for deleting the watch, using
2962  * libhal_device_remove_property_watch, if the device is removed.
2963  *
2964  * Returns: TRUE only if the operation succeeded
2965  */
2966 dbus_bool_t
2967 libhal_device_add_property_watch (LibHalContext *ctx, const char *udi, DBusError *error)
2968 {
2969 	char buf[512];
2970 
2971 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
2972 
2973 	snprintf (buf, 512,
2974 		  "type='signal',"
2975 		  "interface='org.freedesktop.Hal.Device',"
2976 		  "sender='org.freedesktop.Hal'," "path=%s", udi);
2977 
2978 	dbus_bus_add_match (ctx->connection, buf, error);
2979 	if (dbus_error_is_set (error)) {
2980 		return FALSE;
2981 	}
2982 	return TRUE;
2983 }
2984 
2985 
2986 /**
2987  * libhal_device_remove_property_watch:
2988  * @ctx: the context for the connection to hald
2989  * @udi: the Unique Device Id
2990  * @error: pointer to an initialized dbus error object for returning errors or NULL
2991  *
2992  * Remove a watch on a device.
2993  *
2994  * Returns: TRUE only if the operation succeeded
2995  */
2996 dbus_bool_t
2997 libhal_device_remove_property_watch (LibHalContext *ctx, const char *udi, DBusError *error)
2998 {
2999 	char buf[512];
3000 
3001 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3002 
3003 	snprintf (buf, 512,
3004 		  "type='signal',"
3005 		  "interface='org.freedesktop.Hal.Device',"
3006 		  "sender='org.freedesktop.Hal'," "path=%s", udi);
3007 
3008 	dbus_bus_remove_match (ctx->connection, buf, error);
3009 	if (dbus_error_is_set (error)) {
3010 		return FALSE;
3011 	}
3012 	return TRUE;
3013 }
3014 
3015 
3016 /**
3017  * libhal_ctx_new:
3018  *
3019  * Create a new LibHalContext
3020  *
3021  * Returns: a new uninitialized LibHalContext object
3022  */
3023 LibHalContext *
3024 libhal_ctx_new (void)
3025 {
3026 	LibHalContext *ctx;
3027 
3028 	if (!libhal_already_initialized_once) {
3029 		bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
3030 		bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
3031 
3032 		libhal_already_initialized_once = TRUE;
3033 	}
3034 
3035 	ctx = calloc (1, sizeof (LibHalContext));
3036 	if (ctx == NULL) {
3037 		fprintf (stderr,
3038 			 "%s %d : Failed to allocate %d bytes\n",
3039 			 __FILE__, __LINE__, sizeof (LibHalContext));
3040 		return NULL;
3041 	}
3042 
3043 	ctx->is_initialized = FALSE;
3044 	ctx->is_shutdown = FALSE;
3045 	ctx->connection = NULL;
3046 	ctx->is_direct = FALSE;
3047 
3048 	return ctx;
3049 }
3050 
3051 /**
3052  * libhal_ctx_set_cache:
3053  * @ctx: context to enable/disable cache for
3054  * @use_cache: whether or not to use cache
3055  *
3056  * Enable or disable caching. Note: Caching is not actually
3057  * implemented yet.
3058  *
3059  * Returns: TRUE if cache was successfully enabled/disabled, FALSE otherwise
3060  */
3061 dbus_bool_t
3062 libhal_ctx_set_cache (LibHalContext *ctx, dbus_bool_t use_cache)
3063 {
3064 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3065 
3066 	ctx->cache_enabled = use_cache;
3067 	return TRUE;
3068 }
3069 
3070 /**
3071  * libhal_ctx_set_dbus_connection:
3072  * @ctx: context to set connection for
3073  * @conn: DBus connection to use
3074  *
3075  * Set DBus connection to use to talk to hald.
3076  *
3077  * Returns: TRUE if connection was successfully set, FALSE otherwise
3078  */
3079 dbus_bool_t
3080 libhal_ctx_set_dbus_connection (LibHalContext *ctx, DBusConnection *conn)
3081 {
3082 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3083 
3084 	if (conn == NULL)
3085 		return FALSE;
3086 
3087 	ctx->connection = conn;
3088 	return TRUE;
3089 }
3090 
3091 /**
3092  * libhal_ctx_get_dbus_connection:
3093  * @ctx: context to get connection for
3094  *
3095  * Get DBus connection used for talking to hald.
3096  *
3097  * Returns: DBus connection to use or NULL
3098  */
3099 DBusConnection *
3100 libhal_ctx_get_dbus_connection (LibHalContext *ctx)
3101 {
3102 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3103 
3104 	return ctx->connection;
3105 }
3106 
3107 
3108 /**
3109  * libhal_ctx_init:
3110  * @ctx: Context for connection to hald (D-BUS connection should be set with libhal_ctx_set_dbus_connection)
3111  * @error: pointer to an initialized dbus error object for returning errors or NULL
3112  *
3113  * Initialize the connection to hald.
3114  *
3115  * Returns: TRUE if initialization succeeds, FALSE otherwise
3116  */
3117 dbus_bool_t
3118 libhal_ctx_init (LibHalContext *ctx, DBusError *error)
3119 {
3120 	DBusError _error;
3121 	dbus_bool_t hald_exists;
3122 
3123 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3124 
3125 	if (ctx->connection == NULL)
3126 		return FALSE;
3127 
3128 	dbus_error_init (&_error);
3129 	hald_exists = dbus_bus_name_has_owner (ctx->connection, "org.freedesktop.Hal", &_error);
3130 	dbus_move_error (&_error, error);
3131 	if (error != NULL && dbus_error_is_set (error)) {
3132 		return FALSE;
3133 	}
3134 
3135 	if (!hald_exists) {
3136 		return FALSE;
3137 	}
3138 
3139 
3140 	if (!dbus_connection_add_filter (ctx->connection, filter_func, ctx, NULL)) {
3141 		return FALSE;
3142 	}
3143 
3144 	dbus_bus_add_match (ctx->connection,
3145 			    "type='signal',"
3146 			    "interface='org.freedesktop.Hal.Manager',"
3147 			    "sender='org.freedesktop.Hal',"
3148 			    "path='/org/freedesktop/Hal/Manager'", &_error);
3149 	dbus_move_error (&_error, error);
3150 	if (error != NULL && dbus_error_is_set (error)) {
3151 		return FALSE;
3152 	}
3153 	ctx->is_initialized = TRUE;
3154 	ctx->is_direct = FALSE;
3155 
3156 	return TRUE;
3157 }
3158 
3159 /**
3160  * libhal_ctx_init_direct:
3161  * @error: pointer to an initialized dbus error object for returning errors or NULL
3162  *
3163  * Create an already initialized connection to hald. This function should only be used by HAL helpers.
3164  *
3165  * Returns: A pointer to an already initialized LibHalContext
3166  */
3167 LibHalContext *
3168 libhal_ctx_init_direct (DBusError *error)
3169 {
3170 	char *hald_addr;
3171 	LibHalContext *ctx;
3172 	DBusError _error;
3173 
3174 	ctx = libhal_ctx_new ();
3175 	if (ctx == NULL)
3176 		goto out;
3177 
3178 	if (((hald_addr = getenv ("HALD_DIRECT_ADDR"))) == NULL) {
3179 		libhal_ctx_free (ctx);
3180 		ctx = NULL;
3181 		goto out;
3182 	}
3183 
3184 	dbus_error_init (&_error);
3185 	ctx->connection = dbus_connection_open (hald_addr, &_error);
3186 	dbus_move_error (&_error, error);
3187 	if (error != NULL && dbus_error_is_set (error)) {
3188 		libhal_ctx_free (ctx);
3189 		ctx = NULL;
3190 		goto out;
3191 	}
3192 
3193 	ctx->is_initialized = TRUE;
3194 	ctx->is_direct = TRUE;
3195 
3196 out:
3197 	return ctx;
3198 }
3199 
3200 /**
3201  * libhal_ctx_shutdown:
3202  * @ctx: the context for the connection to hald
3203  * @error: pointer to an initialized dbus error object for returning errors or NULL
3204  *
3205  * Shut down a connection to hald.
3206  *
3207  * Returns: TRUE if connection successfully shut down, FALSE otherwise
3208  */
3209 dbus_bool_t
3210 libhal_ctx_shutdown (LibHalContext *ctx, DBusError *error)
3211 {
3212 	DBusError myerror;
3213 
3214 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3215 
3216 	if (ctx->is_direct) {
3217 		/* for some reason dbus_connection_set_exit_on_disconnect doesn't work yet so don't unref */
3218 		/*dbus_connection_unref (ctx->connection);*/
3219 	} else {
3220 		dbus_error_init (&myerror);
3221 		dbus_bus_remove_match (ctx->connection,
3222 				       "type='signal',"
3223 				       "interface='org.freedesktop.Hal.Manager',"
3224 				       "sender='org.freedesktop.Hal',"
3225 				       "path='/org/freedesktop/Hal/Manager'", &myerror);
3226 		dbus_move_error(&myerror, error);
3227 		if (error != NULL && dbus_error_is_set(error)) {
3228 			fprintf (stderr, "%s %d : Error unsubscribing to signals, error=%s\n",
3229 				 __FILE__, __LINE__, error->message);
3230 			/** @todo  clean up */
3231 		}
3232 
3233 		/* TODO: remove other matches */
3234 
3235 		dbus_connection_remove_filter (ctx->connection, filter_func, ctx);
3236 	}
3237 
3238 	ctx->is_initialized = FALSE;
3239 
3240 	return TRUE;
3241 }
3242 
3243 /**
3244  * libhal_ctx_free:
3245  * @ctx: pointer to a LibHalContext
3246  *
3247  * Free a LibHalContext resource.
3248  *
3249  * Returns: TRUE
3250  */
3251 dbus_bool_t
3252 libhal_ctx_free (LibHalContext *ctx)
3253 {
3254 	free (ctx);
3255 	return TRUE;
3256 }
3257 
3258 /**
3259  * libhal_ctx_set_device_added:
3260  * @ctx: the context for the connection to hald
3261  * @callback: the function to call when a device is added
3262  *
3263  * Set the callback for when a device is added
3264  *
3265  * Returns: TRUE if callback was successfully set, FALSE otherwise
3266  */
3267 dbus_bool_t
3268 libhal_ctx_set_device_added (LibHalContext *ctx, LibHalDeviceAdded callback)
3269 {
3270 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3271 
3272 	ctx->device_added = callback;
3273 	return TRUE;
3274 }
3275 
3276 /**
3277  * libhal_ctx_set_device_removed:
3278  * @ctx: the context for the connection to hald
3279  * @callback: the function to call when a device is removed
3280  *
3281  * Set the callback for when a device is removed.
3282  *
3283  * Returns: TRUE if callback was successfully set, FALSE otherwise
3284  */
3285 dbus_bool_t
3286 libhal_ctx_set_device_removed (LibHalContext *ctx, LibHalDeviceRemoved callback)
3287 {
3288 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3289 
3290 	ctx->device_removed = callback;
3291 	return TRUE;
3292 }
3293 
3294 /**
3295  * libhal_ctx_set_device_new_capability:
3296  * @ctx: the context for the connection to hald
3297  * @callback: the function to call when a device gains a new capability
3298  *
3299  * Set the callback for when a device gains a new capability.
3300  *
3301  * Returns: TRUE if callback was successfully set, FALSE otherwise
3302  */
3303 dbus_bool_t
3304 libhal_ctx_set_device_new_capability (LibHalContext *ctx, LibHalDeviceNewCapability callback)
3305 {
3306 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3307 
3308 	ctx->device_new_capability = callback;
3309 	return TRUE;
3310 }
3311 
3312 /**
3313  * libhal_ctx_set_device_lost_capability:
3314  * @ctx: the context for the connection to hald
3315  * @callback: the function to call when a device loses a capability
3316  *
3317  * Set the callback for when a device loses a capability
3318  *
3319  * Returns: TRUE if callback was successfully set, FALSE otherwise
3320  */
3321 dbus_bool_t
3322 libhal_ctx_set_device_lost_capability (LibHalContext *ctx, LibHalDeviceLostCapability callback)
3323 {
3324 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3325 
3326 	ctx->device_lost_capability = callback;
3327 	return TRUE;
3328 }
3329 
3330 /**
3331  * libhal_ctx_set_device_property_modified:
3332  * @ctx: the context for the connection to hald
3333  * @callback: the function to call when a property is modified on a device
3334  *
3335  * Set the callback for when a property is modified on a device.
3336  *
3337  * Returns: TRUE if callback was successfully set, FALSE otherwise
3338  */
3339 dbus_bool_t
3340 libhal_ctx_set_device_property_modified (LibHalContext *ctx, LibHalDevicePropertyModified callback)
3341 {
3342 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3343 
3344 	ctx->device_property_modified = callback;
3345 	return TRUE;
3346 }
3347 
3348 /**
3349  * libhal_ctx_set_device_condition:
3350  * @ctx: the context for the connection to hald
3351  * @callback: the function to call when a device emits a condition
3352  *
3353  * Set the callback for when a device emits a condition
3354  *
3355  * Returns: TRUE if callback was successfully set, FALSE otherwise
3356  */
3357 dbus_bool_t
3358 libhal_ctx_set_device_condition (LibHalContext *ctx, LibHalDeviceCondition callback)
3359 {
3360 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3361 
3362 	ctx->device_condition = callback;
3363 	return TRUE;
3364 }
3365 
3366 /**
3367  * libhal_string_array_length:
3368  * @str_array: array of strings to consider
3369  *
3370  * Get the length of an array of strings.
3371  *
3372  * Returns: Number of strings in array
3373  */
3374 unsigned int
3375 libhal_string_array_length (char **str_array)
3376 {
3377 	unsigned int i;
3378 
3379 	if (str_array == NULL)
3380 		return 0;
3381 
3382 	for (i = 0; str_array[i] != NULL; i++)
3383 		;
3384 
3385 	return i;
3386 }
3387 
3388 
3389 /**
3390  * libhal_device_rescan:
3391  * @ctx: the context for the connection to hald
3392  * @udi: the Unique id of device
3393  * @error: pointer to an initialized dbus error object for returning errors or NULL
3394  *
3395  * TODO document me.
3396  *
3397  * Returns: Whether the operation succeeded
3398  */
3399 dbus_bool_t
3400 libhal_device_rescan (LibHalContext *ctx, const char *udi, DBusError *error)
3401 {
3402 	DBusMessage *message;
3403 	DBusMessageIter reply_iter;
3404 	DBusMessage *reply;
3405 	dbus_bool_t result;
3406 
3407 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3408 
3409 	message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
3410 						"org.freedesktop.Hal.Device",
3411 						"Rescan");
3412 
3413 	if (message == NULL) {
3414 		fprintf (stderr,
3415 			 "%s %d : Couldn't allocate D-BUS message\n",
3416 			 __FILE__, __LINE__);
3417 		return FALSE;
3418 	}
3419 
3420 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
3421 							   message, -1,
3422 							   error);
3423 
3424 	if (dbus_error_is_set (error)) {
3425 		dbus_message_unref (message);
3426 		return FALSE;
3427 	}
3428 
3429 	dbus_message_unref (message);
3430 
3431 	if (reply == NULL)
3432 		return FALSE;
3433 
3434 	dbus_message_iter_init (reply, &reply_iter);
3435 	if (dbus_message_iter_get_arg_type (&reply_iter) !=
3436 		   DBUS_TYPE_BOOLEAN) {
3437 		dbus_message_unref (message);
3438 		dbus_message_unref (reply);
3439 		return FALSE;
3440 	}
3441 	dbus_message_iter_get_basic (&reply_iter, &result);
3442 
3443 	dbus_message_unref (reply);
3444 
3445 	return result;
3446 }
3447 
3448 /**
3449  * libhal_device_reprobe:
3450  * @ctx: the context for the connection to hald
3451  * @udi: the Unique id of device
3452  * @error: pointer to an initialized dbus error object for returning errors or NULL
3453  *
3454  * TODO document me.
3455  *
3456  * Returns: Whether the operation succeeded
3457  */
3458 dbus_bool_t
3459 libhal_device_reprobe (LibHalContext *ctx, const char *udi, DBusError *error)
3460 {
3461 	DBusMessage *message;
3462 	DBusMessageIter reply_iter;
3463 	DBusMessage *reply;
3464 	dbus_bool_t result;
3465 
3466 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3467 
3468 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
3469 						udi,
3470 						"org.freedesktop.Hal.Device",
3471 						"Reprobe");
3472 
3473 	if (message == NULL) {
3474 		fprintf (stderr,
3475 			 "%s %d : Couldn't allocate D-BUS message\n",
3476 			 __FILE__, __LINE__);
3477 		return FALSE;
3478 	}
3479 
3480 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
3481 							   message, -1,
3482 							   error);
3483 
3484 	if (dbus_error_is_set (error)) {
3485 		dbus_message_unref (message);
3486 		return FALSE;
3487 	}
3488 
3489 	dbus_message_unref (message);
3490 
3491 	if (reply == NULL)
3492 		return FALSE;
3493 
3494 	dbus_message_iter_init (reply, &reply_iter);
3495 	if (dbus_message_iter_get_arg_type (&reply_iter) !=
3496 		   DBUS_TYPE_BOOLEAN) {
3497 		dbus_message_unref (message);
3498 		dbus_message_unref (reply);
3499 		return FALSE;
3500 	}
3501 	dbus_message_iter_get_basic (&reply_iter, &result);
3502 
3503 	dbus_message_unref (reply);
3504 
3505 	return result;
3506 }
3507 
3508 /**
3509  * libhal_device_emit_condition:
3510  * @ctx: the context for the connection to hald
3511  * @udi: the Unique Device Id
3512  * @condition_name: user-readable name of condition
3513  * @condition_details: user-readable details of condition
3514  * @error: pointer to an initialized dbus error object for returning errors or NULL
3515  *
3516  * Emit a condition from a device. Can only be used from hald helpers.
3517  *
3518  * Returns: TRUE if condition successfully emitted,
3519  *                              FALSE otherwise
3520  */
3521 dbus_bool_t libhal_device_emit_condition (LibHalContext *ctx,
3522 					  const char *udi,
3523 					  const char *condition_name,
3524 					  const char *condition_details,
3525 					  DBusError *error)
3526 {
3527 	DBusMessage *message;
3528 	DBusMessageIter iter;
3529 	DBusMessageIter reply_iter;
3530 	DBusMessage *reply;
3531 	dbus_bool_t result;
3532 
3533 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3534 
3535 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
3536 						udi,
3537 						"org.freedesktop.Hal.Device",
3538 						"EmitCondition");
3539 
3540 	if (message == NULL) {
3541 		fprintf (stderr,
3542 			 "%s %d : Couldn't allocate D-BUS message\n",
3543 			 __FILE__, __LINE__);
3544 		return FALSE;
3545 	}
3546 
3547 	dbus_message_iter_init_append (message, &iter);
3548 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &condition_name);
3549 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &condition_details);
3550 
3551 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
3552 							   message, -1,
3553 							   error);
3554 
3555 	if (dbus_error_is_set (error)) {
3556 		dbus_message_unref (message);
3557 		return FALSE;
3558 	}
3559 
3560 	dbus_message_unref (message);
3561 
3562 	if (reply == NULL)
3563 		return FALSE;
3564 
3565 	dbus_message_iter_init (reply, &reply_iter);
3566 	if (dbus_message_iter_get_arg_type (&reply_iter) !=
3567 		   DBUS_TYPE_BOOLEAN) {
3568 		dbus_message_unref (message);
3569 		dbus_message_unref (reply);
3570 		return FALSE;
3571 	}
3572 	dbus_message_iter_get_basic (&reply_iter, &result);
3573 
3574 	dbus_message_unref (reply);
3575 
3576 	return result;
3577 }
3578 
3579 /**
3580  * libhal_device_addon_is_ready:
3581  * @ctx: the context for the connection to hald
3582  * @udi: the Unique Device Id
3583  * @error: pointer to an initialized dbus error object for returning errors or NULL
3584  *
3585  * HAL addon's must call this method when they are done initializing the device object. The HAL
3586  * daemon will wait for all addon's to call this.
3587  *
3588  * Can only be used from hald helpers.
3589  *
3590  * Returns: TRUE if the HAL daemon received the message, FALSE otherwise
3591  */
3592 dbus_bool_t
3593 libhal_device_addon_is_ready (LibHalContext *ctx, const char *udi, DBusError *error)
3594 {
3595 	DBusMessage *message;
3596 	DBusMessageIter iter;
3597 	DBusMessageIter reply_iter;
3598 	DBusMessage *reply;
3599 	dbus_bool_t result;
3600 
3601 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3602 
3603 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
3604 						udi,
3605 						"org.freedesktop.Hal.Device",
3606 						"AddonIsReady");
3607 
3608 	if (message == NULL) {
3609 		fprintf (stderr,
3610 			 "%s %d : Couldn't allocate D-BUS message\n",
3611 			 __FILE__, __LINE__);
3612 		return FALSE;
3613 	}
3614 
3615 	dbus_message_iter_init_append (message, &iter);
3616 
3617 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
3618 							   message, -1,
3619 							   error);
3620 
3621 	if (dbus_error_is_set (error)) {
3622 		dbus_message_unref (message);
3623 		return FALSE;
3624 	}
3625 
3626 	dbus_message_unref (message);
3627 
3628 	if (reply == NULL)
3629 		return FALSE;
3630 
3631 	dbus_message_iter_init (reply, &reply_iter);
3632 	if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) {
3633 		dbus_message_unref (message);
3634 		dbus_message_unref (reply);
3635 		return FALSE;
3636 	}
3637 	dbus_message_iter_get_basic (&reply_iter, &result);
3638 
3639 	dbus_message_unref (reply);
3640 	return result;
3641 }
3642 
3643 /**
3644  * libhal_device_claim_interface:
3645  * @ctx: the context for the connection to hald
3646  * @udi: the Unique Device Id
3647  * @interface_name: Name of interface to claim, e.g. org.freedesktop.Hal.Device.FoobarKindOfThing
3648  * @introspection_xml: Introspection XML containing what would be inside the interface XML tag
3649  * @error: pointer to an initialized dbus error object for returning errors or NULL
3650  *
3651  * Claim an interface for a device. All messages to this interface
3652  * will be forwarded to the helper. Can only be used from hald
3653  * helpers.
3654  *
3655  * Returns: TRUE if interface was claimed, FALSE otherwise
3656  */
3657 dbus_bool_t
3658 libhal_device_claim_interface (LibHalContext *ctx,
3659 			       const char *udi,
3660 			       const char *interface_name,
3661 			       const char *introspection_xml,
3662 			       DBusError *error)
3663 {
3664 	DBusMessage *message;
3665 	DBusMessageIter iter;
3666 	DBusMessageIter reply_iter;
3667 	DBusMessage *reply;
3668 	dbus_bool_t result;
3669 
3670 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
3671 
3672 	message = dbus_message_new_method_call ("org.freedesktop.Hal",
3673 						udi,
3674 						"org.freedesktop.Hal.Device",
3675 						"ClaimInterface");
3676 
3677 	if (message == NULL) {
3678 		fprintf (stderr,
3679 			 "%s %d : Couldn't allocate D-BUS message\n",
3680 			 __FILE__, __LINE__);
3681 		return FALSE;
3682 	}
3683 
3684 	dbus_message_iter_init_append (message, &iter);
3685 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface_name);
3686 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &introspection_xml);
3687 
3688 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
3689 							   message, -1,
3690 							   error);
3691 
3692 	if (dbus_error_is_set (error)) {
3693 		dbus_message_unref (message);
3694 		return FALSE;
3695 	}
3696 
3697 	dbus_message_unref (message);
3698 
3699 	if (reply == NULL)
3700 		return FALSE;
3701 
3702 	dbus_message_iter_init (reply, &reply_iter);
3703 	if (dbus_message_iter_get_arg_type (&reply_iter) !=
3704 		   DBUS_TYPE_BOOLEAN) {
3705 		dbus_message_unref (message);
3706 		dbus_message_unref (reply);
3707 		return FALSE;
3708 	}
3709 	dbus_message_iter_get_basic (&reply_iter, &result);
3710 
3711 	dbus_message_unref (reply);
3712 
3713 	return result;
3714 }
3715 
3716 
3717 
3718 struct LibHalChangeSetElement_s;
3719 
3720 typedef struct LibHalChangeSetElement_s LibHalChangeSetElement;
3721 
3722 struct LibHalChangeSetElement_s {
3723 	char *key;
3724 	int change_type;
3725 	union {
3726 		char *val_str;
3727 		dbus_int32_t val_int;
3728 		dbus_uint64_t val_uint64;
3729 		double val_double;
3730 		dbus_bool_t val_bool;
3731 		char **val_strlist;
3732 	} value;
3733 	LibHalChangeSetElement *next;
3734 	LibHalChangeSetElement *prev;
3735 };
3736 
3737 struct LibHalChangeSet_s {
3738 	char *udi;
3739 	LibHalChangeSetElement *head;
3740 	LibHalChangeSetElement *tail;
3741 };
3742 
3743 /**
3744  * libhal_device_new_changeset:
3745  * @udi: unique device identifier
3746  *
3747  * Request a new changeset object. Used for changing multiple properties at once. Useful when
3748  * performance is critical and also for atomically updating several properties.
3749  *
3750  * Returns: A new changeset object or NULL on error
3751  */
3752 LibHalChangeSet *
3753 libhal_device_new_changeset (const char *udi)
3754 {
3755 	LibHalChangeSet *changeset;
3756 
3757 	changeset = calloc (1, sizeof (LibHalChangeSet));
3758 	if (changeset == NULL)
3759 		goto out;
3760 
3761 	changeset->udi = strdup (udi);
3762 	if (changeset->udi == NULL) {
3763 		free (changeset);
3764 		changeset = NULL;
3765 		goto out;
3766 	}
3767 
3768 	changeset->head = NULL;
3769 	changeset->tail = NULL;
3770 
3771 out:
3772 	return changeset;
3773 }
3774 
3775 static void
3776 libhal_changeset_append (LibHalChangeSet *changeset, LibHalChangeSetElement *elem)
3777 {
3778 	if (changeset->head == NULL) {
3779 		changeset->head = elem;
3780 		changeset->tail = elem;
3781 		elem->next = NULL;
3782 		elem->prev = NULL;
3783 	} else {
3784 		elem->prev = changeset->tail;
3785 		elem->next = NULL;
3786 		elem->prev->next = elem;
3787 		changeset->tail = elem;
3788 	}
3789 }
3790 
3791 
3792 /**
3793  * libhal_device_set_property_string:
3794  * @changeset: the changeset
3795  * @key: key of property
3796  * @value: the value to set
3797  *
3798  * Set a property.
3799  *
3800  * Returns: FALSE on OOM
3801  */
3802 dbus_bool_t
3803 libhal_changeset_set_property_string (LibHalChangeSet *changeset, const char *key, const char *value)
3804 {
3805 	LibHalChangeSetElement *elem;
3806 
3807 	elem = calloc (1, sizeof (LibHalChangeSetElement));
3808 	if (elem == NULL)
3809 		goto out;
3810 	elem->key = strdup (key);
3811 	if (elem->key == NULL) {
3812 		free (elem);
3813 		elem = NULL;
3814 		goto out;
3815 	}
3816 
3817 	elem->change_type = LIBHAL_PROPERTY_TYPE_STRING;
3818 	elem->value.val_str = strdup (value);
3819 	if (elem->value.val_str == NULL) {
3820 		free (elem->key);
3821 		free (elem);
3822 		elem = NULL;
3823 		goto out;
3824 	}
3825 
3826 	libhal_changeset_append (changeset, elem);
3827 out:
3828 	return elem != NULL;
3829 }
3830 
3831 /**
3832  * libhal_device_set_property_int:
3833  * @changeset: the changeset
3834  * @key: key of property
3835  * @value: the value to set
3836  *
3837  * Set a property.
3838  *
3839  * Returns: FALSE on OOM
3840  */
3841 dbus_bool_t
3842 libhal_changeset_set_property_int (LibHalChangeSet *changeset, const char *key, dbus_int32_t value)
3843 {
3844 	LibHalChangeSetElement *elem;
3845 
3846 	elem = calloc (1, sizeof (LibHalChangeSetElement));
3847 	if (elem == NULL)
3848 		goto out;
3849 	elem->key = strdup (key);
3850 	if (elem->key == NULL) {
3851 		free (elem);
3852 		elem = NULL;
3853 		goto out;
3854 	}
3855 
3856 	elem->change_type = LIBHAL_PROPERTY_TYPE_INT32;
3857 	elem->value.val_int = value;
3858 
3859 	libhal_changeset_append (changeset, elem);
3860 out:
3861 	return elem != NULL;
3862 }
3863 
3864 /**
3865  * libhal_device_set_property_uint64:
3866  * @changeset: the changeset
3867  * @key: key of property
3868  * @value: the value to set
3869  *
3870  * Set a property.
3871  *
3872  * Returns: FALSE on OOM
3873  */
3874 dbus_bool_t
3875 libhal_changeset_set_property_uint64 (LibHalChangeSet *changeset, const char *key, dbus_uint64_t value)
3876 {
3877 	LibHalChangeSetElement *elem;
3878 
3879 	elem = calloc (1, sizeof (LibHalChangeSetElement));
3880 	if (elem == NULL)
3881 		goto out;
3882 	elem->key = strdup (key);
3883 	if (elem->key == NULL) {
3884 		free (elem);
3885 		elem = NULL;
3886 		goto out;
3887 	}
3888 
3889 	elem->change_type = LIBHAL_PROPERTY_TYPE_UINT64;
3890 	elem->value.val_uint64 = value;
3891 
3892 	libhal_changeset_append (changeset, elem);
3893 out:
3894 	return elem != NULL;
3895 }
3896 
3897 /**
3898  * libhal_device_set_property_double:
3899  * @changeset: the changeset
3900  * @key: key of property
3901  * @value: the value to set
3902  *
3903  * Set a property.
3904  *
3905  * Returns: FALSE on OOM
3906  */
3907 dbus_bool_t
3908 libhal_changeset_set_property_double (LibHalChangeSet *changeset, const char *key, double value)
3909 {
3910 	LibHalChangeSetElement *elem;
3911 
3912 	elem = calloc (1, sizeof (LibHalChangeSetElement));
3913 	if (elem == NULL)
3914 		goto out;
3915 	elem->key = strdup (key);
3916 	if (elem->key == NULL) {
3917 		free (elem);
3918 		elem = NULL;
3919 		goto out;
3920 	}
3921 
3922 	elem->change_type = LIBHAL_PROPERTY_TYPE_DOUBLE;
3923 	elem->value.val_double = value;
3924 
3925 	libhal_changeset_append (changeset, elem);
3926 out:
3927 	return elem != NULL;
3928 }
3929 
3930 /**
3931  * libhal_device_set_property_bool:
3932  * @changeset: the changeset
3933  * @key: key of property
3934  * @value: the value to set
3935  *
3936  * Set a property.
3937  *
3938  * Returns: FALSE on OOM
3939  */
3940 dbus_bool_t
3941 libhal_changeset_set_property_bool (LibHalChangeSet *changeset, const char *key, dbus_bool_t value)
3942 {
3943 	LibHalChangeSetElement *elem;
3944 
3945 	elem = calloc (1, sizeof (LibHalChangeSetElement));
3946 	if (elem == NULL)
3947 		goto out;
3948 	elem->key = strdup (key);
3949 	if (elem->key == NULL) {
3950 		free (elem);
3951 		elem = NULL;
3952 		goto out;
3953 	}
3954 
3955 	elem->change_type = LIBHAL_PROPERTY_TYPE_BOOLEAN;
3956 	elem->value.val_bool = value;
3957 
3958 	libhal_changeset_append (changeset, elem);
3959 out:
3960 	return elem != NULL;
3961 }
3962 
3963 /**
3964  * libhal_device_set_property_strlist:
3965  * @changeset: the changeset
3966  * @key: key of property
3967  * @value: the value to set - NULL terminated array of strings
3968  *
3969  * Set a property.
3970  *
3971  * Returns: FALSE on OOM
3972  */
3973 dbus_bool_t
3974 libhal_changeset_set_property_strlist (LibHalChangeSet *changeset, const char *key, const char **value)
3975 {
3976 	LibHalChangeSetElement *elem;
3977 	char **value_copy;
3978 	int len;
3979 	int i, j;
3980 
3981 	elem = calloc (1, sizeof (LibHalChangeSetElement));
3982 	if (elem == NULL)
3983 		goto out;
3984 	elem->key = strdup (key);
3985 	if (elem->key == NULL) {
3986 		free (elem);
3987 		elem = NULL;
3988 		goto out;
3989 	}
3990 
3991 	for (i = 0; value[i] != NULL; i++)
3992 		;
3993 	len = i;
3994 
3995 	value_copy = calloc (len + 1, sizeof (char *));
3996 	if (value_copy == NULL) {
3997 		free (elem->key);
3998 		free (elem);
3999 		elem = NULL;
4000 		goto out;
4001 	}
4002 
4003 	for (i = 0; i < len; i++) {
4004 		value_copy[i] = strdup (value[i]);
4005 		if (value_copy[i] == NULL) {
4006 			for (j = 0; j < i; j++) {
4007 				free (value_copy[j]);
4008 			}
4009 			free (value_copy);
4010 			free (elem->key);
4011 			free (elem);
4012 			elem = NULL;
4013 			goto out;
4014 		}
4015 	}
4016 	value_copy[i] = NULL;
4017 
4018 	elem->change_type = LIBHAL_PROPERTY_TYPE_STRLIST;
4019 	elem->value.val_strlist = value_copy;
4020 
4021 	libhal_changeset_append (changeset, elem);
4022 out:
4023 	return elem != NULL;
4024 }
4025 
4026 /**
4027  * libhal_device_commit_changeset:
4028  * @ctx: the context for the connection to hald
4029  * @changeset: the changeset to commit
4030  * @error: pointer to an initialized dbus error object for returning errors or NULL
4031  *
4032  * Commit a changeset to the daemon.
4033  *
4034  * Returns: True if the changeset was committed on the daemon side
4035  */
4036 dbus_bool_t
4037 libhal_device_commit_changeset (LibHalContext *ctx, LibHalChangeSet *changeset, DBusError *error)
4038 {
4039 	LibHalChangeSetElement *elem;
4040 	DBusMessage *message;
4041 	DBusMessage *reply;
4042 	DBusError _error;
4043 	DBusMessageIter iter;
4044 	DBusMessageIter sub;
4045 	DBusMessageIter sub2;
4046 	DBusMessageIter sub3;
4047 	DBusMessageIter sub4;
4048 	int i;
4049 
4050 	LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
4051 
4052 	if (changeset->head == NULL) {
4053 		return TRUE;
4054 	}
4055 
4056 	message = dbus_message_new_method_call ("org.freedesktop.Hal", changeset->udi,
4057 						"org.freedesktop.Hal.Device",
4058 						"SetMultipleProperties");
4059 
4060 	if (message == NULL) {
4061 		fprintf (stderr, "%s %d : Couldn't allocate D-BUS message\n", __FILE__, __LINE__);
4062 		return FALSE;
4063 	}
4064 
4065 	dbus_message_iter_init_append (message, &iter);
4066 
4067 	dbus_message_iter_open_container (&iter,
4068 					  DBUS_TYPE_ARRAY,
4069 					  DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
4070 					  DBUS_TYPE_STRING_AS_STRING
4071 					  DBUS_TYPE_VARIANT_AS_STRING
4072 					  DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
4073 					  &sub);
4074 
4075 	for (elem = changeset->head; elem != NULL; elem = elem->next) {
4076 		dbus_message_iter_open_container (&sub,
4077 						  DBUS_TYPE_DICT_ENTRY,
4078 						  NULL,
4079 						  &sub2);
4080 		dbus_message_iter_append_basic (&sub2, DBUS_TYPE_STRING, &(elem->key));
4081 
4082 		switch (elem->change_type) {
4083 		case LIBHAL_PROPERTY_TYPE_STRING:
4084 			dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &sub3);
4085 			dbus_message_iter_append_basic (&sub3, DBUS_TYPE_STRING, &(elem->value.val_str));
4086 			dbus_message_iter_close_container (&sub2, &sub3);
4087 			break;
4088 		case LIBHAL_PROPERTY_TYPE_STRLIST:
4089 			dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT,
4090 							  DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING, &sub3);
4091 			dbus_message_iter_open_container (&sub3, DBUS_TYPE_ARRAY,
4092 							  DBUS_TYPE_STRING_AS_STRING, &sub4);
4093 			for (i = 0; elem->value.val_strlist[i] != NULL; i++) {
4094 				dbus_message_iter_append_basic (&sub4, DBUS_TYPE_STRING,
4095 								&(elem->value.val_strlist[i]));
4096 			}
4097 			dbus_message_iter_close_container (&sub3, &sub4);
4098 			dbus_message_iter_close_container (&sub2, &sub3);
4099 			break;
4100 		case LIBHAL_PROPERTY_TYPE_INT32:
4101 			dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_INT32_AS_STRING, &sub3);
4102 			dbus_message_iter_append_basic (&sub3, DBUS_TYPE_INT32, &(elem->value.val_int));
4103 			dbus_message_iter_close_container (&sub2, &sub3);
4104 			break;
4105 		case LIBHAL_PROPERTY_TYPE_UINT64:
4106 			dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_UINT64_AS_STRING, &sub3);
4107 			dbus_message_iter_append_basic (&sub3, DBUS_TYPE_UINT64, &(elem->value.val_uint64));
4108 			dbus_message_iter_close_container (&sub2, &sub3);
4109 			break;
4110 		case LIBHAL_PROPERTY_TYPE_DOUBLE:
4111 			dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_DOUBLE_AS_STRING, &sub3);
4112 			dbus_message_iter_append_basic (&sub3, DBUS_TYPE_DOUBLE, &(elem->value.val_double));
4113 			dbus_message_iter_close_container (&sub2, &sub3);
4114 			break;
4115 		case LIBHAL_PROPERTY_TYPE_BOOLEAN:
4116 			dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_BOOLEAN_AS_STRING,&sub3);
4117 			dbus_message_iter_append_basic (&sub3, DBUS_TYPE_BOOLEAN, &(elem->value.val_bool));
4118 			dbus_message_iter_close_container (&sub2, &sub3);
4119 			break;
4120 		default:
4121 			fprintf (stderr, "%s %d : unknown change_type %d\n", __FILE__, __LINE__, elem->change_type);
4122 			break;
4123 		}
4124 		dbus_message_iter_close_container (&sub, &sub2);
4125 	}
4126 
4127 	dbus_message_iter_close_container (&iter, &sub);
4128 
4129 
4130 	dbus_error_init (&_error);
4131 	reply = dbus_connection_send_with_reply_and_block (ctx->connection,
4132 							   message, -1,
4133 							   &_error);
4134 
4135 	dbus_move_error (&_error, error);
4136 	if (error != NULL && dbus_error_is_set (error)) {
4137 		fprintf (stderr,
4138 			 "%s %d : %s\n",
4139 			 __FILE__, __LINE__, error->message);
4140 
4141 		dbus_message_unref (message);
4142 		return FALSE;
4143 	}
4144 
4145 	if (reply == NULL) {
4146 		dbus_message_unref (message);
4147 		return FALSE;
4148 	}
4149 
4150 	return TRUE;
4151 }
4152 
4153 /**
4154  * libhal_device_free_changeset:
4155  * @changeset: the changeset to free
4156  *
4157  * Free a changeset.
4158  */
4159 void
4160 libhal_device_free_changeset (LibHalChangeSet *changeset)
4161 {
4162 	LibHalChangeSetElement *elem;
4163 	LibHalChangeSetElement *elem2;
4164 
4165 	for (elem = changeset->head; elem != NULL; elem = elem2) {
4166 		elem2 = elem->next;
4167 
4168 		switch (elem->change_type) {
4169 		case LIBHAL_PROPERTY_TYPE_STRING:
4170 			free (elem->value.val_str);
4171 			break;
4172 		case LIBHAL_PROPERTY_TYPE_STRLIST:
4173 			libhal_free_string_array (elem->value.val_strlist);
4174 			break;
4175                 /* explicit fallthrough */
4176 		case LIBHAL_PROPERTY_TYPE_INT32:
4177 		case LIBHAL_PROPERTY_TYPE_UINT64:
4178 		case LIBHAL_PROPERTY_TYPE_DOUBLE:
4179 		case LIBHAL_PROPERTY_TYPE_BOOLEAN:
4180 			break;
4181 		default:
4182 			fprintf (stderr, "%s %d : unknown change_type %d\n", __FILE__, __LINE__, elem->change_type);
4183 			break;
4184 		}
4185 		free (elem);
4186 	}
4187 
4188 	free (changeset->udi);
4189 	free (changeset);
4190 }
4191