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