Home | History | Annotate | Download | only in hald
      1 /***************************************************************************
      2  * CVSID: $Id$
      3  *
      4  * device.c : HalDevice methods
      5  *
      6  * Copyright (C) 2003 David Zeuthen, <david (at) fubar.dk>
      7  * Copyright (C) 2004 Novell, Inc.
      8  *
      9  * Licensed under the Academic Free License version 2.1
     10  *
     11  * This program is free software; you can redistribute it and/or modify
     12  * it under the terms of the GNU General Public License as published by
     13  * the Free Software Foundation; either version 2 of the License, or
     14  * (at your option) any later version.
     15  *
     16  * This program is distributed in the hope that it will be useful,
     17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     19  * GNU General Public License for more details.
     20  *
     21  * You should have received a copy of the GNU General Public License
     22  * along with this program; if not, write to the Free Software
     23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     24  *
     25  **************************************************************************/
     26 
     27 #ifdef HAVE_CONFIG_H
     28 #  include <config.h>
     29 #endif
     30 
     31 #include <stdio.h>
     32 #include <string.h>
     33 
     34 #include "hald.h"
     35 #include "device.h"
     36 #include "hald_marshal.h"
     37 #include "logger.h"
     38 #include "hald_runner.h"
     39 
     40 static GObjectClass *parent_class;
     41 
     42 enum {
     43 	PROPERTY_CHANGED,
     44 	CAPABILITY_ADDED,
     45 	CALLOUTS_FINISHED,
     46 	CANCELLED,
     47 	LAST_SIGNAL
     48 };
     49 
     50 static guint signals[LAST_SIGNAL] = { 0 };
     51 
     52 #ifdef HALD_MEMLEAK_DBG
     53 int dbg_hal_device_object_delta = 0;
     54 #endif
     55 
     56 static void
     57 hal_device_finalize (GObject *obj)
     58 {
     59 	HalDevice *device = HAL_DEVICE (obj);
     60 
     61 	runner_device_finalized (device);
     62 
     63 #ifdef HALD_MEMLEAK_DBG
     64 	dbg_hal_device_object_delta--;
     65 	printf ("************* in finalize for udi=%s\n", device->udi);
     66 #endif
     67 
     68 
     69 	g_slist_foreach (device->properties, (GFunc) hal_property_free, NULL);
     70 
     71 	g_slist_free (device->properties);
     72 
     73 	g_free (device->udi);
     74 
     75 	if (parent_class->finalize)
     76 		parent_class->finalize (obj);
     77 
     78 }
     79 
     80 static void
     81 hal_device_class_init (HalDeviceClass *klass)
     82 {
     83 	GObjectClass *obj_class = (GObjectClass *) klass;
     84 
     85 	parent_class = g_type_class_peek_parent (klass);
     86 
     87 	obj_class->finalize = hal_device_finalize;
     88 
     89 	signals[PROPERTY_CHANGED] =
     90 		g_signal_new ("property_changed",
     91 			      G_TYPE_FROM_CLASS (klass),
     92 			      G_SIGNAL_RUN_LAST,
     93 			      G_STRUCT_OFFSET (HalDeviceClass,
     94 					       property_changed),
     95 			      NULL, NULL,
     96 			      hald_marshal_VOID__STRING_BOOL_BOOL,
     97 			      G_TYPE_NONE, 3,
     98 			      G_TYPE_STRING,
     99 			      G_TYPE_BOOLEAN,
    100 			      G_TYPE_BOOLEAN);
    101 
    102 	signals[CAPABILITY_ADDED] =
    103 		g_signal_new ("capability_added",
    104 			      G_TYPE_FROM_CLASS (klass),
    105 			      G_SIGNAL_RUN_LAST,
    106 			      G_STRUCT_OFFSET (HalDeviceClass,
    107 					       capability_added),
    108 			      NULL, NULL,
    109 			      hald_marshal_VOID__STRING,
    110 			      G_TYPE_NONE, 1,
    111 			      G_TYPE_STRING);
    112 
    113 	signals[CALLOUTS_FINISHED] =
    114 		g_signal_new ("callouts_finished",
    115 			      G_TYPE_FROM_CLASS (klass),
    116 			      G_SIGNAL_RUN_LAST,
    117 			      G_STRUCT_OFFSET (HalDeviceClass,
    118 					       callouts_finished),
    119 			      NULL, NULL,
    120 			      hald_marshal_VOID__VOID,
    121 			      G_TYPE_NONE, 0);
    122 
    123 	signals[CANCELLED] =
    124 		g_signal_new ("cancelled",
    125 			      G_TYPE_FROM_CLASS (klass),
    126 			      G_SIGNAL_RUN_LAST,
    127 			      G_STRUCT_OFFSET (HalDeviceClass,
    128 					       cancelled),
    129 			      NULL, NULL,
    130 			      hald_marshal_VOID__VOID,
    131 			      G_TYPE_NONE, 0);
    132 }
    133 
    134 static void
    135 hal_device_init (HalDevice *device)
    136 {
    137 	static int temp_device_counter = 0;
    138 
    139 	device->udi = g_strdup_printf ("/org/freedesktop/Hal/devices/temp/%d",
    140 				       temp_device_counter++);
    141 	device->num_addons = 0;
    142 	device->num_addons_ready = 0;
    143 }
    144 
    145 GType
    146 hal_device_get_type (void)
    147 {
    148 	static GType type = 0;
    149 
    150 	if (!type) {
    151 		static GTypeInfo type_info = {
    152 			sizeof (HalDeviceClass),
    153 			NULL, NULL,
    154 			(GClassInitFunc) hal_device_class_init,
    155 			NULL, NULL,
    156 			sizeof (HalDevice),
    157 			0,
    158 			(GInstanceInitFunc) hal_device_init,
    159 			NULL
    160 		};
    161 
    162 		type = g_type_register_static (G_TYPE_OBJECT,
    163 					       "HalDevice",
    164 					       &type_info,
    165 					       0);
    166 	}
    167 
    168 	return type;
    169 }
    170 
    171 
    172 HalDevice *
    173 hal_device_new (void)
    174 {
    175 	HalDevice *device;
    176 
    177 	device = g_object_new (HAL_TYPE_DEVICE, NULL, NULL);
    178 
    179 #ifdef HALD_MEMLEAK_DBG
    180 	dbg_hal_device_object_delta++;
    181 #endif
    182 	return device;
    183 }
    184 
    185 /** Merge all properties from source where the key starts with
    186  *  source_namespace and put them onto target replacing source_namespace
    187  *  with target_namespace
    188  *
    189  *  @param  target              Device to put properties onto
    190  *  @param  source              Device to retrieve properties from
    191  *  @param  target_namespace    Replace source namespace with this namespace
    192  *  @param  source_namespace    Source namespace that property keys must match
    193  */
    194 void
    195 hal_device_merge_with_rewrite  (HalDevice    *target,
    196 				HalDevice    *source,
    197 				const char   *target_namespace,
    198 				const char   *source_namespace)
    199 {
    200 	GSList *iter;
    201 	size_t source_ns_len;
    202 
    203 	source_ns_len = strlen (source_namespace);
    204 
    205 	/* doesn't handle info.capabilities */
    206 
    207 	/* device_property_atomic_update_begin (); */
    208 
    209 	for (iter = source->properties; iter != NULL; iter = iter->next) {
    210 		HalProperty *p = iter->data;
    211 		int type;
    212 		const char *key;
    213 		int target_type;
    214 		gchar *target_key;
    215 
    216 		key = hal_property_get_key (p);
    217 
    218 		/* only care about properties that match source namespace */
    219 		if (strncmp(key, source_namespace, source_ns_len) != 0)
    220 			continue;
    221 
    222 		target_key = g_strdup_printf("%s%s", target_namespace,
    223 					     key+source_ns_len);
    224 
    225 		type = hal_property_get_type (p);
    226 
    227 		/* only remove target if it exists with a different type */
    228 		target_type = hal_device_property_get_type (target, key);
    229 		if (target_type != HAL_PROPERTY_TYPE_INVALID && target_type != type)
    230 			hal_device_property_remove (target, key);
    231 
    232 		switch (type) {
    233 
    234 		case HAL_PROPERTY_TYPE_STRING:
    235 			hal_device_property_set_string (
    236 				target, target_key,
    237 				hal_property_get_string (p));
    238 			break;
    239 
    240 		case HAL_PROPERTY_TYPE_INT32:
    241 			hal_device_property_set_int (
    242 				target, target_key,
    243 				hal_property_get_int (p));
    244 			break;
    245 
    246 		case HAL_PROPERTY_TYPE_UINT64:
    247 			hal_device_property_set_uint64 (
    248 				target, target_key,
    249 				hal_property_get_uint64 (p));
    250 			break;
    251 
    252 		case HAL_PROPERTY_TYPE_BOOLEAN:
    253 			hal_device_property_set_bool (
    254 				target, target_key,
    255 				hal_property_get_bool (p));
    256 			break;
    257 
    258 		case HAL_PROPERTY_TYPE_DOUBLE:
    259 			hal_device_property_set_double (
    260 				target, target_key,
    261 				hal_property_get_double (p));
    262 			break;
    263 
    264 		default:
    265 			HAL_WARNING (("Unknown property type %d", type));
    266 			break;
    267 		}
    268 
    269 		g_free (target_key);
    270 	}
    271 
    272 	/* device_property_atomic_update_end (); */
    273 
    274 }
    275 
    276 void
    277 hal_device_merge (HalDevice *target, HalDevice *source)
    278 {
    279 	GSList *iter;
    280 	GSList *caps;
    281 
    282 	/* device_property_atomic_update_begin (); */
    283 
    284 	for (iter = source->properties; iter != NULL; iter = iter->next) {
    285 		HalProperty *p = iter->data;
    286 		int type;
    287 		const char *key;
    288 		int target_type;
    289 
    290 		key = hal_property_get_key (p);
    291 		type = hal_property_get_type (p);
    292 
    293 		/* handle info.capabilities in a special way */
    294 		if (strcmp (key, "info.capabilities") == 0)
    295 			continue;
    296 
    297 		/* only remove target if it exists with a different type */
    298 		target_type = hal_device_property_get_type (target, key);
    299 		if (target_type != HAL_PROPERTY_TYPE_INVALID && target_type != type)
    300 			hal_device_property_remove (target, key);
    301 
    302 		switch (type) {
    303 
    304 		case HAL_PROPERTY_TYPE_STRING:
    305 			hal_device_property_set_string (
    306 				target, key,
    307 				hal_property_get_string (p));
    308 			break;
    309 
    310 		case HAL_PROPERTY_TYPE_INT32:
    311 			hal_device_property_set_int (
    312 				target, key,
    313 				hal_property_get_int (p));
    314 			break;
    315 
    316 		case HAL_PROPERTY_TYPE_UINT64:
    317 			hal_device_property_set_uint64 (
    318 				target, key,
    319 				hal_property_get_uint64 (p));
    320 			break;
    321 
    322 		case HAL_PROPERTY_TYPE_BOOLEAN:
    323 			hal_device_property_set_bool (
    324 				target, key,
    325 				hal_property_get_bool (p));
    326 			break;
    327 
    328 		case HAL_PROPERTY_TYPE_DOUBLE:
    329 			hal_device_property_set_double (
    330 				target, key,
    331 				hal_property_get_double (p));
    332 			break;
    333 
    334 		default:
    335 			HAL_WARNING (("Unknown property type %d", type));
    336 			break;
    337 		}
    338 	}
    339 
    340 	/* device_property_atomic_update_end (); */
    341 
    342 	caps = hal_device_property_get_strlist (source, "info.capabilities");
    343 	for (iter = caps; iter != NULL; iter = iter->next) {
    344 		if (!hal_device_has_capability (target, iter->data))
    345 			hal_device_add_capability (target, iter->data);
    346 	}
    347 }
    348 
    349 gboolean
    350 hal_device_matches (HalDevice *device1, HalDevice *device2,
    351 		    const char *namespace)
    352 {
    353 	int len;
    354 	GSList *iter;
    355 
    356 	len = strlen (namespace);
    357 
    358 	for (iter = device1->properties; iter != NULL; iter = iter->next) {
    359 		HalProperty *p;
    360 		const char *key;
    361 		int type;
    362 
    363 		p = (HalProperty *) iter->data;
    364 		key = hal_property_get_key (p);
    365 		type = hal_property_get_type (p);
    366 
    367 		if (strncmp (key, namespace, len) != 0)
    368 			continue;
    369 
    370 		if (!hal_device_has_property (device2, key))
    371 			return FALSE;
    372 
    373 		switch (type) {
    374 
    375 		case HAL_PROPERTY_TYPE_STRING:
    376 			if (strcmp (hal_property_get_string (p),
    377 				    hal_device_property_get_string (device2,
    378 								    key)) != 0)
    379 				return FALSE;
    380 			break;
    381 
    382 		case HAL_PROPERTY_TYPE_INT32:
    383 			if (hal_property_get_int (p) !=
    384 			    hal_device_property_get_int (device2, key))
    385 				return FALSE;
    386 			break;
    387 
    388 		case HAL_PROPERTY_TYPE_UINT64:
    389 			if (hal_property_get_uint64 (p) !=
    390 				hal_device_property_get_uint64 (device2, key))
    391 				return FALSE;
    392 			break;
    393 
    394 		case HAL_PROPERTY_TYPE_BOOLEAN:
    395 			if (hal_property_get_bool (p) !=
    396 			    hal_device_property_get_bool (device2, key))
    397 				return FALSE;
    398 			break;
    399 
    400 		case HAL_PROPERTY_TYPE_DOUBLE:
    401 			if (hal_property_get_double (p) !=
    402 			    hal_device_property_get_double (device2, key))
    403 				return FALSE;
    404 			break;
    405 
    406 		default:
    407 			HAL_WARNING (("Unknown property type %d", type));
    408 			break;
    409 		}
    410 	}
    411 
    412 	return TRUE;
    413 }
    414 
    415 const char *
    416 hal_device_get_udi (HalDevice *device)
    417 {
    418 	return device->udi;
    419 }
    420 
    421 void
    422 hal_device_set_udi (HalDevice *device, const char *udi)
    423 {
    424 	if (device->udi != NULL)
    425 		g_free (device->udi);
    426 	device->udi = g_strdup (udi);
    427 }
    428 
    429 void
    430 hal_device_add_capability (HalDevice *device, const char *capability)
    431 {
    432 	if (hal_device_property_strlist_add (device, "info.capabilities", capability))
    433 		g_signal_emit (device, signals[CAPABILITY_ADDED], 0, capability);
    434 }
    435 
    436 gboolean
    437 hal_device_has_capability (HalDevice *device, const char *capability)
    438 {
    439 	GSList *caps;
    440 	GSList *iter;
    441 	gboolean matched = FALSE;
    442 
    443 	caps = hal_device_property_get_strlist (device, "info.capabilities");
    444 
    445 	if (caps == NULL)
    446 		return FALSE;
    447 
    448 	for (iter = caps; iter != NULL; iter = iter->next) {
    449 		if (strcmp (iter->data, capability) == 0) {
    450 			matched = TRUE;
    451 			break;
    452 		}
    453 	}
    454 
    455 	return matched;
    456 }
    457 
    458 gboolean
    459 hal_device_has_property (HalDevice *device, const char *key)
    460 {
    461 	g_return_val_if_fail (device != NULL, FALSE);
    462 	g_return_val_if_fail (key != NULL, FALSE);
    463 
    464 	return hal_device_property_find (device, key) != NULL;
    465 }
    466 
    467 int
    468 hal_device_num_properties (HalDevice *device)
    469 {
    470 	g_return_val_if_fail (device != NULL, -1);
    471 
    472 	return g_slist_length (device->properties);
    473 }
    474 
    475 HalProperty *
    476 hal_device_property_find (HalDevice *device, const char *key)
    477 {
    478 	GSList *iter;
    479 
    480 	g_return_val_if_fail (device != NULL, NULL);
    481 	g_return_val_if_fail (key != NULL, NULL);
    482 
    483 	for (iter = device->properties; iter != NULL; iter = iter->next) {
    484 		HalProperty *p = iter->data;
    485 
    486 		if (strcmp (hal_property_get_key (p), key) == 0)
    487 			return p;
    488 	}
    489 
    490 	return NULL;
    491 }
    492 
    493 char *
    494 hal_device_property_to_string (HalDevice *device, const char *key)
    495 {
    496 	HalProperty *prop;
    497 
    498 	prop = hal_device_property_find (device, key);
    499 	if (!prop)
    500 		return NULL;
    501 
    502 	return hal_property_to_string (prop);
    503 }
    504 
    505 void
    506 hal_device_property_foreach (HalDevice *device,
    507 			     HalDevicePropertyForeachFn callback,
    508 			     gpointer user_data)
    509 {
    510 	GSList *iter;
    511 
    512 	g_return_if_fail (device != NULL);
    513 	g_return_if_fail (callback != NULL);
    514 
    515 	for (iter = device->properties; iter != NULL; iter = iter->next) {
    516 		HalProperty *p = iter->data;
    517 		gboolean cont;
    518 
    519 		cont = callback (device, p, user_data);
    520 
    521 		if (cont == FALSE)
    522 			return;
    523 	}
    524 }
    525 
    526 int
    527 hal_device_property_get_type (HalDevice *device, const char *key)
    528 {
    529 	HalProperty *prop;
    530 
    531 	g_return_val_if_fail (device != NULL, HAL_PROPERTY_TYPE_INVALID);
    532 	g_return_val_if_fail (key != NULL, HAL_PROPERTY_TYPE_INVALID);
    533 
    534 	prop = hal_device_property_find (device, key);
    535 
    536 	if (prop != NULL)
    537 		return hal_property_get_type (prop);
    538 	else
    539 		return HAL_PROPERTY_TYPE_INVALID;
    540 }
    541 
    542 const char *
    543 hal_device_property_get_string (HalDevice *device, const char *key)
    544 {
    545 	HalProperty *prop;
    546 
    547 	g_return_val_if_fail (device != NULL, NULL);
    548 	g_return_val_if_fail (key != NULL, NULL);
    549 
    550 	prop = hal_device_property_find (device, key);
    551 
    552 	if (prop != NULL)
    553 		return hal_property_get_string (prop);
    554 	else
    555 		return NULL;
    556 }
    557 
    558 const char *
    559 hal_device_property_get_as_string (HalDevice *device, const char *key, char *buf, size_t bufsize)
    560 {
    561 	HalProperty *prop;
    562 
    563 	g_return_val_if_fail (device != NULL, NULL);
    564 	g_return_val_if_fail (key != NULL, NULL);
    565 	g_return_val_if_fail (buf != NULL, NULL);
    566 
    567 	prop = hal_device_property_find (device, key);
    568 
    569 	if (prop != NULL) {
    570 		switch (hal_property_get_type (prop)) {
    571 		case HAL_PROPERTY_TYPE_STRING:
    572 			strncpy (buf, hal_property_get_string (prop), bufsize);
    573 			break;
    574 		case HAL_PROPERTY_TYPE_INT32:
    575 			snprintf (buf, bufsize, "%d", hal_property_get_int (prop));
    576 			break;
    577 		case HAL_PROPERTY_TYPE_UINT64:
    578 			snprintf (buf, bufsize, "%llu", (long long unsigned int) hal_property_get_uint64 (prop));
    579 			break;
    580 		case HAL_PROPERTY_TYPE_DOUBLE:
    581 			snprintf (buf, bufsize, "%f", hal_property_get_double (prop));
    582 			break;
    583 		case HAL_PROPERTY_TYPE_BOOLEAN:
    584 			strncpy (buf, hal_property_get_bool (prop) ? "true" : "false", bufsize);
    585 			break;
    586 
    587 		case HAL_PROPERTY_TYPE_STRLIST:
    588 			/* print out as "\tval1\tval2\val3\t" */
    589 		        {
    590 				GSList *iter;
    591 				guint i;
    592 
    593 				if (bufsize > 0)
    594 					buf[0] = '\t';
    595 				i = 1;
    596 				for (iter = hal_property_get_strlist (prop);
    597 				     iter != NULL && i < bufsize;
    598 				     iter = g_slist_next (iter)) {
    599 					guint len;
    600 					const char *str;
    601 
    602 					str = (const char *) iter->data;
    603 					len = strlen (str);
    604 					strncpy (buf + i, str, bufsize - i);
    605 					i += len;
    606 
    607 					if (i < bufsize) {
    608 						buf[i] = '\t';
    609 						i++;
    610 					}
    611 				}
    612 			}
    613 			break;
    614 		}
    615 		return buf;
    616 	} else {
    617 		buf[0] = '\0';
    618 		return NULL;
    619 	}
    620 }
    621 
    622 dbus_int32_t
    623 hal_device_property_get_int (HalDevice *device, const char *key)
    624 {
    625 	HalProperty *prop;
    626 
    627 	g_return_val_if_fail (device != NULL, -1);
    628 	g_return_val_if_fail (key != NULL, -1);
    629 
    630 	prop = hal_device_property_find (device, key);
    631 
    632 	if (prop != NULL)
    633 		return hal_property_get_int (prop);
    634 	else
    635 		return -1;
    636 }
    637 
    638 dbus_uint64_t
    639 hal_device_property_get_uint64 (HalDevice *device, const char *key)
    640 {
    641 	HalProperty *prop;
    642 
    643 	g_return_val_if_fail (device != NULL, -1);
    644 	g_return_val_if_fail (key != NULL, -1);
    645 
    646 	prop = hal_device_property_find (device, key);
    647 
    648 	if (prop != NULL)
    649 		return hal_property_get_uint64 (prop);
    650 	else
    651 		return -1;
    652 }
    653 
    654 dbus_bool_t
    655 hal_device_property_get_bool (HalDevice *device, const char *key)
    656 {
    657 	HalProperty *prop;
    658 
    659 	g_return_val_if_fail (device != NULL, FALSE);
    660 	g_return_val_if_fail (key != NULL, FALSE);
    661 
    662 	prop = hal_device_property_find (device, key);
    663 
    664 	if (prop != NULL)
    665 		return hal_property_get_bool (prop);
    666 	else
    667 		return FALSE;
    668 }
    669 
    670 double
    671 hal_device_property_get_double (HalDevice *device, const char *key)
    672 {
    673 	HalProperty *prop;
    674 
    675 	g_return_val_if_fail (device != NULL, -1.0);
    676 	g_return_val_if_fail (key != NULL, -1.0);
    677 
    678 	prop = hal_device_property_find (device, key);
    679 
    680 	if (prop != NULL)
    681 		return hal_property_get_double (prop);
    682 	else
    683 		return -1.0;
    684 }
    685 
    686 gboolean
    687 hal_device_property_set_string (HalDevice *device, const char *key,
    688 				const char *value)
    689 {
    690 	HalProperty *prop;
    691 
    692 	/* check if property already exists */
    693 	prop = hal_device_property_find (device, key);
    694 
    695 	if (prop != NULL) {
    696 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_STRING)
    697 			return FALSE;
    698 
    699 		/* don't bother setting the same value */
    700 		if (value != NULL &&
    701 		    strcmp (hal_property_get_string (prop), value) == 0)
    702 			return TRUE;
    703 
    704 		hal_property_set_string (prop, value);
    705 
    706 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
    707 			       key, FALSE, FALSE);
    708 
    709 	} else {
    710 
    711 		prop = hal_property_new_string (key, value);
    712 
    713 		device->properties = g_slist_prepend (device->properties, prop);
    714 
    715 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
    716 			       key, FALSE, TRUE);
    717 	}
    718 
    719 	return TRUE;
    720 }
    721 
    722 gboolean
    723 hal_device_property_set_int (HalDevice *device, const char *key,
    724 			     dbus_int32_t value)
    725 {
    726 	HalProperty *prop;
    727 
    728 	/* check if property already exists */
    729 	prop = hal_device_property_find (device, key);
    730 
    731 	if (prop != NULL) {
    732 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_INT32)
    733 			return FALSE;
    734 
    735 		/* don't bother setting the same value */
    736 		if (hal_property_get_int (prop) == value)
    737 			return TRUE;
    738 
    739 		hal_property_set_int (prop, value);
    740 
    741 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
    742 			       key, FALSE, FALSE);
    743 
    744 	} else {
    745 		prop = hal_property_new_int (key, value);
    746 
    747 		device->properties = g_slist_prepend (device->properties, prop);
    748 
    749 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
    750 			       key, FALSE, TRUE);
    751 	}
    752 
    753 	return TRUE;
    754 }
    755 
    756 gboolean
    757 hal_device_property_set_uint64 (HalDevice *device, const char *key,
    758 			     dbus_uint64_t value)
    759 {
    760 	HalProperty *prop;
    761 
    762 	/* check if property already exists */
    763 	prop = hal_device_property_find (device, key);
    764 
    765 	if (prop != NULL) {
    766 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_UINT64)
    767 			return FALSE;
    768 
    769 		/* don't bother setting the same value */
    770 		if (hal_property_get_uint64 (prop) == value)
    771 			return TRUE;
    772 
    773 		hal_property_set_uint64 (prop, value);
    774 
    775 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
    776 			       key, FALSE, FALSE);
    777 
    778 	} else {
    779 		prop = hal_property_new_uint64 (key, value);
    780 
    781 		device->properties = g_slist_prepend (device->properties, prop);
    782 
    783 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
    784 			       key, FALSE, TRUE);
    785 	}
    786 
    787 	return TRUE;
    788 }
    789 
    790 gboolean
    791 hal_device_property_set_bool (HalDevice *device, const char *key,
    792 			     dbus_bool_t value)
    793 {
    794 	HalProperty *prop;
    795 
    796 	/* check if property already exists */
    797 	prop = hal_device_property_find (device, key);
    798 
    799 	if (prop != NULL) {
    800 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_BOOLEAN)
    801 			return FALSE;
    802 
    803 		/* don't bother setting the same value */
    804 		if (hal_property_get_bool (prop) == value)
    805 			return TRUE;
    806 
    807 		hal_property_set_bool (prop, value);
    808 
    809 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
    810 			       key, FALSE, FALSE);
    811 
    812 	} else {
    813 		prop = hal_property_new_bool (key, value);
    814 
    815 		device->properties = g_slist_prepend (device->properties, prop);
    816 
    817 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
    818 			       key, FALSE, TRUE);
    819 	}
    820 
    821 	return TRUE;
    822 }
    823 
    824 gboolean
    825 hal_device_property_set_double (HalDevice *device, const char *key,
    826 				double value)
    827 {
    828 	HalProperty *prop;
    829 
    830 	/* check if property already exists */
    831 	prop = hal_device_property_find (device, key);
    832 
    833 	if (prop != NULL) {
    834 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_DOUBLE)
    835 			return FALSE;
    836 
    837 		/* don't bother setting the same value */
    838 		if (hal_property_get_double (prop) == value)
    839 			return TRUE;
    840 
    841 		hal_property_set_double (prop, value);
    842 
    843 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
    844 			       key, FALSE, FALSE);
    845 
    846 	} else {
    847 		prop = hal_property_new_double (key, value);
    848 
    849 		device->properties = g_slist_prepend (device->properties, prop);
    850 
    851 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
    852 			       key, FALSE, TRUE);
    853 	}
    854 
    855 	return TRUE;
    856 }
    857 
    858 gboolean
    859 hal_device_copy_property (HalDevice *from_device, const char *from, HalDevice *to_device, const char *to)
    860 {
    861 	gboolean rc;
    862 
    863 	rc = FALSE;
    864 
    865 	if (hal_device_has_property (from_device, from)) {
    866 		switch (hal_device_property_get_type (from_device, from)) {
    867 		case HAL_PROPERTY_TYPE_STRING:
    868 			rc = hal_device_property_set_string (
    869 				to_device, to, hal_device_property_get_string (from_device, from));
    870 			break;
    871 		case HAL_PROPERTY_TYPE_INT32:
    872 			rc = hal_device_property_set_int (
    873 				to_device, to, hal_device_property_get_int (from_device, from));
    874 			break;
    875 		case HAL_PROPERTY_TYPE_UINT64:
    876 			rc = hal_device_property_set_uint64 (
    877 				to_device, to, hal_device_property_get_uint64 (from_device, from));
    878 			break;
    879 		case HAL_PROPERTY_TYPE_BOOLEAN:
    880 			rc = hal_device_property_set_bool (
    881 				to_device, to, hal_device_property_get_bool (from_device, from));
    882 			break;
    883 		case HAL_PROPERTY_TYPE_DOUBLE:
    884 			rc = hal_device_property_set_double (
    885 				to_device, to, hal_device_property_get_double (from_device, from));
    886 			break;
    887 		}
    888 	}
    889 
    890 	return rc;
    891 }
    892 
    893 gboolean
    894 hal_device_property_remove (HalDevice *device, const char *key)
    895 {
    896 	HalProperty *prop;
    897 
    898 	prop = hal_device_property_find (device, key);
    899 
    900 	if (prop == NULL)
    901 		return FALSE;
    902 
    903 	device->properties = g_slist_remove (device->properties, prop);
    904 
    905 	hal_property_free (prop);
    906 
    907 	g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
    908 		       key, TRUE, FALSE);
    909 
    910 	return TRUE;
    911 }
    912 
    913 gboolean
    914 hal_device_property_set_attribute (HalDevice *device,
    915 				   const char *key,
    916 				   enum PropertyAttribute attr,
    917 				   gboolean val)
    918 {
    919 	HalProperty *prop;
    920 
    921 	prop = hal_device_property_find (device, key);
    922 
    923 	if (prop == NULL)
    924 		return FALSE;
    925 
    926 	return TRUE;
    927 }
    928 
    929 void
    930 hal_device_print (HalDevice *device)
    931 {
    932 	GSList *iter;
    933 
    934         fprintf (stderr, "device udi = %s\n", hal_device_get_udi (device));
    935 
    936 	for (iter = device->properties; iter != NULL; iter = iter->next) {
    937 		HalProperty *p = iter->data;
    938                 int type;
    939                 const char *key;
    940 
    941                 key = hal_property_get_key (p);
    942                 type = hal_property_get_type (p);
    943 
    944                 switch (type) {
    945                 case HAL_PROPERTY_TYPE_STRING:
    946                         fprintf (stderr, "  %s = '%s'  (string)\n", key,
    947                                 hal_property_get_string (p));
    948                         break;
    949 
    950                 case HAL_PROPERTY_TYPE_INT32:
    951                         fprintf (stderr, "  %s = %d  0x%x  (int)\n", key,
    952                                 hal_property_get_int (p),
    953                                 hal_property_get_int (p));
    954                         break;
    955 
    956                 case HAL_PROPERTY_TYPE_UINT64:
    957                         fprintf (stderr, "  %s = %llu  0x%llx  (uint64)\n", key,
    958                                 (long long unsigned int) hal_property_get_uint64 (p),
    959                                 (long long unsigned int) hal_property_get_uint64 (p));
    960                         break;
    961 
    962                 case HAL_PROPERTY_TYPE_DOUBLE:
    963                         fprintf (stderr, "  %s = %g  (double)\n", key,
    964                                 hal_property_get_double (p));
    965                         break;
    966 
    967                 case HAL_PROPERTY_TYPE_BOOLEAN:
    968                         fprintf (stderr, "  %s = %s  (bool)\n", key,
    969                                 (hal_property_get_bool (p) ? "true" :
    970                                  "false"));
    971                         break;
    972 
    973                 default:
    974                         HAL_WARNING (("Unknown property type %d", type));
    975                         break;
    976                 }
    977         }
    978         fprintf (stderr, "\n");
    979 }
    980 
    981 
    982 typedef struct {
    983 	char *key;
    984 	HalDevice *device;
    985 	HalDeviceAsyncCallback callback;
    986 	gpointer user_data;
    987 
    988 	guint prop_signal_id;
    989 	guint timeout_id;
    990 } AsyncMatchInfo;
    991 
    992 static void
    993 destroy_async_match_info (AsyncMatchInfo *ai)
    994 {
    995 	g_free (ai->key);
    996 	g_signal_handler_disconnect (ai->device, ai->prop_signal_id);
    997 	g_source_remove (ai->timeout_id);
    998 	g_object_unref (ai->device);
    999 	g_free (ai);
   1000 }
   1001 
   1002 static void
   1003 prop_changed_cb (HalDevice *device, const char *key,
   1004 		 gboolean removed, gboolean added, gpointer user_data)
   1005 {
   1006 	AsyncMatchInfo *ai = user_data;
   1007 
   1008 	if (strcmp (key, ai->key) != 0)
   1009 		return;
   1010 
   1011 	/* the property is no longer there */
   1012 	if (removed)
   1013 		goto cleanup;
   1014 
   1015 
   1016 	ai->callback (ai->device, ai->user_data, TRUE);
   1017 
   1018 cleanup:
   1019 	destroy_async_match_info (ai);
   1020 }
   1021 
   1022 
   1023 static gboolean
   1024 async_wait_timeout (gpointer user_data)
   1025 {
   1026 	AsyncMatchInfo *ai = (AsyncMatchInfo *) user_data;
   1027 
   1028 	ai->callback (ai->device, ai->user_data, FALSE);
   1029 
   1030 	destroy_async_match_info (ai);
   1031 
   1032 	return FALSE;
   1033 }
   1034 
   1035 void
   1036 hal_device_async_wait_property (HalDevice    *device,
   1037 				const char   *key,
   1038 				HalDeviceAsyncCallback callback,
   1039 				gpointer     user_data,
   1040 				int          timeout)
   1041 {
   1042 	HalProperty *prop;
   1043 	AsyncMatchInfo *ai;
   1044 
   1045 	/* check if property already exists */
   1046 	prop = hal_device_property_find (device, key);
   1047 
   1048 	if (prop != NULL || timeout==0) {
   1049 		callback (device, user_data, prop != NULL);
   1050 		return;
   1051 	}
   1052 
   1053 	ai = g_new0 (AsyncMatchInfo, 1);
   1054 
   1055 	ai->device = g_object_ref (device);
   1056 	ai->key = g_strdup (key);
   1057 	ai->callback = callback;
   1058 	ai->user_data = user_data;
   1059 
   1060 	ai->prop_signal_id = g_signal_connect (device, "property_changed",
   1061 					       G_CALLBACK (prop_changed_cb),
   1062 					       ai);
   1063 
   1064 	ai->timeout_id = g_timeout_add (timeout, async_wait_timeout, ai);
   1065 }
   1066 
   1067 void
   1068 hal_device_callouts_finished (HalDevice *device)
   1069 {
   1070 	g_signal_emit (device, signals[CALLOUTS_FINISHED], 0);
   1071 }
   1072 
   1073 /** Used when giving up on a device, e.g. if no device file appeared
   1074  */
   1075 void
   1076 hal_device_cancel (HalDevice *device)
   1077 {
   1078 	HAL_INFO (("udi=%s", device->udi));
   1079 	g_signal_emit (device, signals[CANCELLED], 0);
   1080 }
   1081 
   1082 
   1083 
   1084 
   1085 GSList *
   1086 hal_device_property_get_strlist (HalDevice    *device,
   1087 				 const char   *key)
   1088 {
   1089 	HalProperty *prop;
   1090 
   1091 	g_return_val_if_fail (device != NULL, NULL);
   1092 	g_return_val_if_fail (key != NULL, NULL);
   1093 
   1094 	prop = hal_device_property_find (device, key);
   1095 
   1096 	if (prop != NULL)
   1097 		return hal_property_get_strlist (prop);
   1098 	else
   1099 		return NULL;
   1100 }
   1101 
   1102 const char *
   1103 hal_device_property_get_strlist_elem (HalDevice    *device,
   1104 				      const char   *key,
   1105 				      guint index)
   1106 {
   1107 	GSList *strlist;
   1108 	GSList *i;
   1109 
   1110 	strlist = hal_device_property_get_strlist (device, key);
   1111 	if (strlist == NULL)
   1112 		return NULL;
   1113 
   1114 	i = g_slist_nth (strlist, index);
   1115 	if (i == NULL)
   1116 		return NULL;
   1117 
   1118 	return (const char *) i->data;
   1119 }
   1120 
   1121 gboolean
   1122 hal_device_property_strlist_append (HalDevice    *device,
   1123 				    const char   *key,
   1124 				    const char *value)
   1125 {
   1126 	HalProperty *prop;
   1127 
   1128 	/* check if property already exists */
   1129 	prop = hal_device_property_find (device, key);
   1130 
   1131 	if (prop != NULL) {
   1132 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_STRLIST)
   1133 			return FALSE;
   1134 
   1135 		hal_property_strlist_append (prop, value);
   1136 
   1137 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
   1138 			       key, FALSE, FALSE);
   1139 
   1140 	} else {
   1141 		prop = hal_property_new_strlist (key);
   1142 		hal_property_strlist_append (prop, value);
   1143 
   1144 		device->properties = g_slist_prepend (device->properties, prop);
   1145 
   1146 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
   1147 			       key, FALSE, TRUE);
   1148 	}
   1149 
   1150 	return TRUE;
   1151 }
   1152 
   1153 gboolean
   1154 hal_device_property_strlist_prepend (HalDevice    *device,
   1155 				     const char   *key,
   1156 				     const char *value)
   1157 {
   1158 	HalProperty *prop;
   1159 
   1160 	/* check if property already exists */
   1161 	prop = hal_device_property_find (device, key);
   1162 
   1163 	if (prop != NULL) {
   1164 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_STRLIST)
   1165 			return FALSE;
   1166 
   1167 		hal_property_strlist_prepend (prop, value);
   1168 
   1169 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
   1170 			       key, FALSE, FALSE);
   1171 
   1172 	} else {
   1173 		prop = hal_property_new_strlist (key);
   1174 		hal_property_strlist_prepend (prop, value);
   1175 
   1176 		device->properties = g_slist_prepend (device->properties, prop);
   1177 
   1178 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
   1179 			       key, FALSE, TRUE);
   1180 	}
   1181 
   1182 	return TRUE;
   1183 }
   1184 
   1185 gboolean
   1186 hal_device_property_strlist_remove_elem (HalDevice    *device,
   1187 					 const char   *key,
   1188 					 guint index)
   1189 {
   1190 	HalProperty *prop;
   1191 
   1192 	/* check if property already exists */
   1193 	prop = hal_device_property_find (device, key);
   1194 
   1195 	if (prop == NULL)
   1196 		return FALSE;
   1197 
   1198 	if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_STRLIST)
   1199 		return FALSE;
   1200 
   1201 	if (hal_property_strlist_remove_elem (prop, index)) {
   1202 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
   1203 			       key, FALSE, FALSE);
   1204 		return TRUE;
   1205 	}
   1206 
   1207 	return FALSE;
   1208 }
   1209 
   1210 gboolean
   1211 hal_device_property_strlist_clear (HalDevice    *device,
   1212 				   const char   *key)
   1213 {
   1214 	HalProperty *prop;
   1215 
   1216 	/* check if property already exists */
   1217 	prop = hal_device_property_find (device, key);
   1218 
   1219 	if (prop == NULL) {
   1220 		prop = hal_property_new_strlist (key);
   1221 
   1222 		device->properties = g_slist_prepend (device->properties, prop);
   1223 
   1224 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
   1225 			       key, FALSE, TRUE);
   1226 
   1227 		return TRUE;
   1228 	}
   1229 
   1230 	if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_STRLIST)
   1231 		return FALSE;
   1232 
   1233 	if (hal_property_strlist_clear (prop)) {
   1234 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
   1235 			       key, FALSE, FALSE);
   1236 		return TRUE;
   1237 	}
   1238 
   1239 	return FALSE;
   1240 }
   1241 
   1242 
   1243 gboolean
   1244 hal_device_property_strlist_add (HalDevice *device,
   1245 				 const char *key,
   1246 				 const char *value)
   1247 {
   1248 	HalProperty *prop;
   1249 	gboolean res;
   1250 
   1251 	res = FALSE;
   1252 
   1253 	/* check if property already exists */
   1254 	prop = hal_device_property_find (device, key);
   1255 
   1256 	if (prop != NULL) {
   1257 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_STRLIST)
   1258 			goto out;
   1259 
   1260 		res = hal_property_strlist_add (prop, value);
   1261 		if (res) {
   1262 			g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
   1263 				       key, FALSE, FALSE);
   1264 		}
   1265 
   1266 	} else {
   1267 		prop = hal_property_new_strlist (key);
   1268 		hal_property_strlist_prepend (prop, value);
   1269 
   1270 		device->properties = g_slist_prepend (device->properties, prop);
   1271 
   1272 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
   1273 			       key, FALSE, TRUE);
   1274 
   1275 		res = TRUE;
   1276 	}
   1277 
   1278 out:
   1279 	return res;
   1280 }
   1281 
   1282 gboolean
   1283 hal_device_property_strlist_remove (HalDevice *device,
   1284 				    const char *key,
   1285 				    const char *value)
   1286 {
   1287 	HalProperty *prop;
   1288 
   1289 	/* check if property already exists */
   1290 	prop = hal_device_property_find (device, key);
   1291 
   1292 	if (prop == NULL)
   1293 		return FALSE;
   1294 
   1295 	if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_STRLIST)
   1296 		return FALSE;
   1297 
   1298 	if (hal_property_strlist_remove (prop, value)) {
   1299 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
   1300 			       key, FALSE, FALSE);
   1301 	}
   1302 
   1303 	return TRUE;
   1304 }
   1305 
   1306 gboolean
   1307 hal_device_property_strlist_is_empty (HalDevice    *device,
   1308 				      const char   *key)
   1309 {
   1310 	GSList *strlist;
   1311 
   1312 	if ( hal_device_has_property (device, key)) {
   1313 		strlist = hal_device_property_get_strlist (device, key);
   1314 		if (strlist == NULL )
   1315 			return TRUE;
   1316 
   1317 		if (g_slist_length (strlist) > 0)
   1318 			return FALSE;
   1319 		else
   1320 			return TRUE;
   1321 	}
   1322 	return FALSE;
   1323 }
   1324 
   1325 void
   1326 hal_device_inc_num_addons (HalDevice *device)
   1327 {
   1328 	device->num_addons++;
   1329 }
   1330 
   1331 gboolean
   1332 hal_device_inc_num_ready_addons (HalDevice *device)
   1333 {
   1334 	if (hal_device_are_all_addons_ready (device)) {
   1335 		HAL_ERROR (("In hal_device_inc_num_ready_addons for udi=%s but all addons are already ready!",
   1336 			    device->udi));
   1337 		return FALSE;
   1338 	}
   1339 
   1340 	device->num_addons_ready++;
   1341 	return TRUE;
   1342 }
   1343 
   1344 gboolean
   1345 hal_device_are_all_addons_ready (HalDevice *device)
   1346 {
   1347 	if (device->num_addons_ready == device->num_addons) {
   1348 		return TRUE;
   1349 	} else {
   1350 		return FALSE;
   1351 	}
   1352 }
   1353