1 /***************************************************************************
   2  * CVSID: $Id$
   3  *
   4  * device.c : HalDevice methods
   5  *
   6  * Copyright (C) 2003 David Zeuthen, <david@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_BOOLEAN_BOOLEAN,
  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 }