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