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