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