/***************************************************************************
* CVSID: $Id$
*
* libhal.c : HAL daemon C convenience library
*
* Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
* Copyright (C) 2007 Codethink Ltd. Author Rob Taylor <rob.taylor@codethink.co.uk>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
**************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dbus/dbus.h>
#include "libhal.h"
#ifdef ENABLE_NLS
# include <libintl.h>
# define _(String) dgettext (GETTEXT_PACKAGE, String)
# ifdef gettext_noop
# define N_(String) gettext_noop (String)
# else
# define N_(String) (String)
# endif
#else
/* Stubs that do something close enough. */
# define textdomain(String) (String)
# define gettext(String) (String)
# define dgettext(Domain,Message) (Message)
# define dcgettext(Domain,Message,Type) (Message)
# define bindtextdomain(Domain,Directory) (Domain)
# define _(String)
# define N_(String) (String)
#endif
/**
* LIBHAL_CHECK_PARAM_VALID:
* @_param_: the prameter to check for
* @_name_: the name of the prameter (for debug output)
* @_ret_: what to use for return value if the prameter is NULL
*
* Handy macro for checking whether a parameter is valid and not NULL.
*/
#define LIBHAL_CHECK_PARAM_VALID(_param_,_name_,_ret_) \
do { \
if (_param_ == NULL) { \
fprintf (stderr, \
"%s %d : invalid parameter. %s is NULL.\n", \
__FILE__, __LINE__, _name_); \
return _ret_; \
} \
} while(0)
static char **libhal_get_string_array_from_iter (DBusMessageIter *iter, int *num_elements);
static dbus_bool_t libhal_property_fill_value_from_variant (LibHalProperty *p, DBusMessageIter *var_iter);
/**
* libhal_free_string_array:
* @str_array: the array to be freed
*
* Frees a NULL-terminated array of strings. If passed NULL, does nothing.
*/
void
libhal_free_string_array (char **str_array)
{
if (str_array != NULL) {
int i;
for (i = 0; str_array[i] != NULL; i++) {
free (str_array[i]);
str_array[i] = NULL;
}
free (str_array);
str_array = NULL;
}
}
/**
* libhal_get_string_array_from_iter:
* @iter: the message iterator to extract the strings from
* @num_elements: pointer to an integer where to store number of elements (can be NULL)
*
* Creates a NULL terminated array of strings from a dbus message iterator.
*
* Returns: pointer to the string array
*/
static char **
libhal_get_string_array_from_iter (DBusMessageIter *iter, int *num_elements)
{
int count;
char **buffer;
count = 0;
buffer = (char **)malloc (sizeof (char *) * 8);
if (buffer == NULL)
goto oom;
buffer[0] = NULL;
while (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_STRING) {
const char *value;
char *str;
if ((count % 8) == 0 && count != 0) {
buffer = realloc (buffer, sizeof (char *) * (count + 8));
if (buffer == NULL)
goto oom;
}
dbus_message_iter_get_basic (iter, &value);
str = strdup (value);
if (str == NULL)
goto oom;
buffer[count] = str;
dbus_message_iter_next(iter);
count++;
}
if ((count % 8) == 0) {
buffer = realloc (buffer, sizeof (char *) * (count + 1));
if (buffer == NULL)
goto oom;
}
buffer[count] = NULL;
if (num_elements != NULL)
*num_elements = count;
return buffer;
oom:
fprintf (stderr, "%s %d : error allocating memory\n", __FILE__, __LINE__);
return NULL;
}
/**
* libhal_free_string:
* @str: the nul-terminated sting to free
*
* Used to free strings returned by libhal.
*/
void
libhal_free_string (char *str)
{
if (str != NULL) {
free (str);
str = NULL;
}
}
/**
* LibHalPropertySet:
*
* Represents a set of properties. Opaque; use the
* libhal_property_set_*() family of functions to access it.
*/
struct LibHalPropertySet_s {
unsigned int num_properties; /**< Number of properties in set */
LibHalProperty *properties_head;
/**< Pointer to first property or NULL
* if there are no properties */
};
/**
* LibHalProperty:
*
* Represents a property. Opaque.
*/
struct LibHalProperty_s {
int type; /**< Type of property */
char *key; /**< ASCII string */
/** Possible values of the property */
union {
char *str_value; /**< UTF-8 zero-terminated string */
dbus_int32_t int_value;
/**< 32-bit signed integer */
dbus_uint64_t uint64_value;
/**< 64-bit unsigned integer */
double double_value; /**< IEEE754 double precision float */
dbus_bool_t bool_value;
/**< Truth value */
char **strlist_value; /**< List of UTF-8 zero-terminated strings */
} v;
LibHalProperty *next; /**< Next property or NULL if this is
* the last */
};
/**
* LibHalContext:
*
* Context for connection to the HAL daemon. Opaque, use the
* libhal_ctx_*() family of functions to access it.
*/
struct LibHalContext_s {
DBusConnection *connection; /**< D-BUS connection */
dbus_bool_t is_initialized; /**< Are we initialised */
dbus_bool_t is_shutdown; /**< Have we been shutdown */
dbus_bool_t cache_enabled; /**< Is the cache enabled */
dbus_bool_t is_direct; /**< Whether the connection to hald is direct */
/** Device added */
LibHalDeviceAdded device_added;
/** Device removed */
LibHalDeviceRemoved device_removed;
/** Device got a new capability */
LibHalDeviceNewCapability device_new_capability;
/** Device got a new capability */
LibHalDeviceLostCapability device_lost_capability;
/** A property of a device changed */
LibHalDevicePropertyModified device_property_modified;
/** A non-continous event on the device occured */
LibHalDeviceCondition device_condition;
void *user_data; /**< User data */
};
/**
* libhal_ctx_set_user_data:
* @ctx: the context for the connection to hald
* @user_data: user data
*
* Set user data for the context.
*
* Returns: TRUE if user data was successfully set, FALSE if otherwise
*/
dbus_bool_t
libhal_ctx_set_user_data(LibHalContext *ctx, void *user_data)
{
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
ctx->user_data = user_data;
return TRUE;
}
/**
* libhal_ctx_get_user_data:
* @ctx: the context for the connection to hald
*
* Get user data for the context.
*
* Returns: opaque pointer stored through libhal_ctx_set_user_data() or NULL if not set.
*/
void*
libhal_ctx_get_user_data(LibHalContext *ctx)
{
LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
return ctx->user_data;
}
/**
* libhal_property_fill_value_from_variant:
* @p: the property to fill in
* @var_iter: variant iterator to extract the value from
*
* Fills in the value for the LibHalProperty given a variant iterator.
*
* Returns: Whether the value was put in.
*/
static dbus_bool_t
libhal_property_fill_value_from_variant (LibHalProperty *p, DBusMessageIter *var_iter)
{
DBusMessageIter iter_array;
switch (p->type) {
case DBUS_TYPE_ARRAY:
if (dbus_message_iter_get_element_type (var_iter) != DBUS_TYPE_STRING)
return FALSE;
dbus_message_iter_recurse (var_iter, &iter_array);
p->v.strlist_value = libhal_get_string_array_from_iter (&iter_array, NULL);
p->type = LIBHAL_PROPERTY_TYPE_STRLIST;
break;
case DBUS_TYPE_STRING:
{
const char *v;
dbus_message_iter_get_basic (var_iter, &v);
p->v.str_value = strdup (v);
if (p->v.str_value == NULL)
return FALSE;
p->type = LIBHAL_PROPERTY_TYPE_STRING;
break;
}
case DBUS_TYPE_INT32:
{
dbus_int32_t v;
dbus_message_iter_get_basic (var_iter, &v);
p->v.int_value = v;
p->type = LIBHAL_PROPERTY_TYPE_INT32;
break;
}
case DBUS_TYPE_UINT64:
{
dbus_uint64_t v;
dbus_message_iter_get_basic (var_iter, &v);
p->v.uint64_value = v;
p->type = LIBHAL_PROPERTY_TYPE_UINT64;
break;
}
case DBUS_TYPE_DOUBLE:
{
double v;
dbus_message_iter_get_basic (var_iter, &v);
p->v.double_value = v;
p->type = LIBHAL_PROPERTY_TYPE_DOUBLE;
break;
}
case DBUS_TYPE_BOOLEAN:
{
double v;
dbus_message_iter_get_basic (var_iter, &v);
p->v.double_value = v;
p->type = LIBHAL_PROPERTY_TYPE_BOOLEAN;
break;
}
default:
/** @todo report error */
break;
}
return TRUE;
}
/**
* libhal_device_get_all_properties:
* @ctx: the context for the connection to hald
* @udi: the Unique id of device
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Retrieve all the properties on a device.
*
* Returns: An object represent all properties. Must be freed with libhal_free_property_set().
*/
LibHalPropertySet *
libhal_device_get_all_properties (LibHalContext *ctx, const char *udi, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter reply_iter;
DBusMessageIter dict_iter;
LibHalPropertySet *result;
LibHalProperty *p_last;
DBusError _error;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"GetAllProperties");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return NULL;
}
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
&_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
fprintf (stderr,
"%s %d : %s\n",
__FILE__, __LINE__, error->message);
dbus_message_unref (message);
return NULL;
}
if (reply == NULL) {
dbus_message_unref (message);
return NULL;
}
dbus_message_iter_init (reply, &reply_iter);
result = malloc (sizeof (LibHalPropertySet));
if (result == NULL)
goto oom;
/*
result->properties = malloc(sizeof(LibHalProperty)*result->num_properties);
if( result->properties==NULL )
{
/// @todo cleanup
return NULL;
}
*/
result->properties_head = NULL;
result->num_properties = 0;
if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY &&
dbus_message_iter_get_element_type (&reply_iter) != DBUS_TYPE_DICT_ENTRY) {
fprintf (stderr, "%s %d : error, expecting an array of dict entries\n",
__FILE__, __LINE__);
dbus_message_unref (message);
dbus_message_unref (reply);
return NULL;
}
dbus_message_iter_recurse (&reply_iter, &dict_iter);
p_last = NULL;
while (dbus_message_iter_get_arg_type (&dict_iter) == DBUS_TYPE_DICT_ENTRY)
{
DBusMessageIter dict_entry_iter, var_iter;
const char *key;
LibHalProperty *p;
dbus_message_iter_recurse (&dict_iter, &dict_entry_iter);
dbus_message_iter_get_basic (&dict_entry_iter, &key);
p = malloc (sizeof (LibHalProperty));
if (p == NULL)
goto oom;
p->next = NULL;
if (result->num_properties == 0)
result->properties_head = p;
if (p_last != NULL)
p_last->next = p;
p_last = p;
p->key = strdup (key);
if (p->key == NULL)
goto oom;
dbus_message_iter_next (&dict_entry_iter);
dbus_message_iter_recurse (&dict_entry_iter, &var_iter);
p->type = dbus_message_iter_get_arg_type (&var_iter);
result->num_properties++;
if(!libhal_property_fill_value_from_variant (p, &var_iter))
goto oom;
dbus_message_iter_next (&dict_iter);
}
dbus_message_unref (message);
dbus_message_unref (reply);
return result;
oom:
fprintf (stderr,
"%s %d : error allocating memory\n",
__FILE__, __LINE__);
/** @todo FIXME cleanup */
return NULL;
}
/**
* libhal_free_property_set:
* @set: property-set to free
*
* Free a property set earlier obtained with libhal_device_get_all_properties().
*/
void
libhal_free_property_set (LibHalPropertySet * set)
{
LibHalProperty *p;
LibHalProperty *q;
if (set == NULL)
return;
for (p = set->properties_head; p != NULL; p = q) {
free (p->key);
if (p->type == DBUS_TYPE_STRING)
free (p->v.str_value);
if (p->type == LIBHAL_PROPERTY_TYPE_STRLIST)
libhal_free_string_array (p->v.strlist_value);
q = p->next;
free (p);
}
free (set);
}
/**
* libhal_property_set_get_num_elems:
* @set: property set to consider
*
* Get the number of properties in a property set.
*
* Returns: number of properties in given property set
*/
unsigned int
libhal_property_set_get_num_elems (LibHalPropertySet *set)
{
unsigned int num_elems;
LibHalProperty *p;
if (set == NULL)
return 0;
num_elems = 0;
for (p = set->properties_head; p != NULL; p = p->next)
num_elems++;
return num_elems;
}
static LibHalProperty *
property_set_lookup (const LibHalPropertySet *set, const char *key)
{
LibHalProperty *p;
LIBHAL_CHECK_PARAM_VALID(set, "*set", NULL);
LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL);
for (p = set->properties_head; p != NULL; p = p->next)
if (strcmp (key, p->key) == 0)
return p;
return NULL;
}
/**
* libhal_ps_get_type:
* @set: property set
* @key: name of property to inspect
*
* Get the type of a given property.
*
* Returns: the #LibHalPropertyType of the given property,
* LIBHAL_PROPERTY_TYPE_INVALID if property is not in the set
*/
LibHalPropertyType
libhal_ps_get_type (const LibHalPropertySet *set, const char *key)
{
LibHalProperty *p = property_set_lookup (set, key);
LIBHAL_CHECK_PARAM_VALID(set, "*set", LIBHAL_PROPERTY_TYPE_INVALID);
LIBHAL_CHECK_PARAM_VALID(key, "*key", LIBHAL_PROPERTY_TYPE_INVALID);
p = property_set_lookup (set, key);
if (p) return p->type;
else return LIBHAL_PROPERTY_TYPE_INVALID;
}
/**
* libhal_ps_get_string:
* @set: property set
* @key: name of property to inspect
*
* Get the value of a property of type string.
*
* Returns: UTF8 nul-terminated string. This pointer is only valid
* until libhal_free_property_set() is invoked on the property set
* this property belongs to. NULL if property is not in the set or not a string
*/
const char *
libhal_ps_get_string (const LibHalPropertySet *set, const char *key)
{
LibHalProperty *p;
LIBHAL_CHECK_PARAM_VALID(set, "*set", NULL);
LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL);
p = property_set_lookup (set, key);
if (p && p->type == LIBHAL_PROPERTY_TYPE_STRING)
return p->v.str_value;
else return NULL;
}
/**
* libhal_ps_get_int:
* @set: property set
* @key: name of property to inspect
*
* Get the value of a property of type signed integer.
*
* Returns: property value (32-bit signed integer)
*/
dbus_int32_t
libhal_ps_get_int32 (const LibHalPropertySet *set, const char *key)
{
LibHalProperty *p;
LIBHAL_CHECK_PARAM_VALID(set, "*set", 0);
LIBHAL_CHECK_PARAM_VALID(key, "*key", 0);
p = property_set_lookup (set, key);
if (p && p->type == LIBHAL_PROPERTY_TYPE_INT32)
return p->v.int_value;
else return 0;
}
/**
* libhal_ps_get_uint64:
* @set: property set
* @key: name of property to inspect
*
* Get the value of a property of type unsigned integer.
*
* Returns: property value (64-bit unsigned integer)
*/
dbus_uint64_t
libhal_ps_get_uint64 (const LibHalPropertySet *set, const char *key)
{
LibHalProperty *p;
LIBHAL_CHECK_PARAM_VALID(set, "*set", 0);
LIBHAL_CHECK_PARAM_VALID(key, "*key", 0);
p = property_set_lookup (set, key);
if (p && p->type == LIBHAL_PROPERTY_TYPE_UINT64)
return p->v.uint64_value;
else return 0;
}
/**
* libhal_ps_get_double:
* @set: property set
* @key: name of property to inspect
*
* Get the value of a property of type double.
*
* Returns: property value (IEEE754 double precision float)
*/
double
libhal_ps_get_double (const LibHalPropertySet *set, const char *key)
{
LibHalProperty *p;
LIBHAL_CHECK_PARAM_VALID(set, "*set", 0.0);
LIBHAL_CHECK_PARAM_VALID(key, "*key", 0.0);
p = property_set_lookup (set, key);
if (p && p->type == LIBHAL_PROPERTY_TYPE_DOUBLE)
return p->v.double_value;
else return 0.0;
}
/**
* libhal_ps_get_bool:
* @set: property set
* @key: name of property to inspect
*
* Get the value of a property of type bool.
*
* Returns: property value (bool)
*/
dbus_bool_t
libhal_ps_get_bool (const LibHalPropertySet *set, const char *key)
{
LibHalProperty *p;
LIBHAL_CHECK_PARAM_VALID(set, "*set", FALSE);
LIBHAL_CHECK_PARAM_VALID(key, "*key", FALSE);
p = property_set_lookup (set, key);
if (p && p->type == LIBHAL_PROPERTY_TYPE_BOOLEAN)
return p->v.bool_value;
else return FALSE;
}
/**
* libhal_ps_get_strlist:
* @set: property set
* @key: name of property to inspect
*
* Get the value of a property of type string list.
*
* Returns: pointer to array of strings, this is owned by the property set
*/
const char *const *
libhal_ps_get_strlist (const LibHalPropertySet *set, const char *key)
{
LibHalProperty *p;
LIBHAL_CHECK_PARAM_VALID(set, "*set", NULL);
LIBHAL_CHECK_PARAM_VALID(key, "*key", NULL);
p = property_set_lookup (set, key);
if (p && p->type == LIBHAL_PROPERTY_TYPE_STRLIST)
return (const char *const *) p->v.strlist_value;
else return NULL;
}
/**
* libhal_psi_init:
* @iter: iterator object
* @set: property set to iterate over
*
* Initialize a property set iterator.
*
*/
void
libhal_psi_init (LibHalPropertySetIterator * iter, LibHalPropertySet * set)
{
if (set == NULL)
return;
iter->set = set;
iter->idx = 0;
iter->cur_prop = set->properties_head;
}
/**
* libhal_psi_has_more:
* @iter: iterator object
*
* Determine whether there are more properties to iterate over.
*
* Returns: TRUE if there are more properties, FALSE otherwise.
*/
dbus_bool_t
libhal_psi_has_more (LibHalPropertySetIterator * iter)
{
return iter->idx < iter->set->num_properties;
}
/**
* libhal_psi_next:
* @iter: iterator object
*
* Advance iterator to next property.
*/
void
libhal_psi_next (LibHalPropertySetIterator * iter)
{
iter->idx++;
iter->cur_prop = iter->cur_prop->next;
}
/**
* libhal_psi_get_type:
* @iter: iterator object
*
* Get type of property.
*
* Returns: the property type at the iterator's position
*/
LibHalPropertyType
libhal_psi_get_type (LibHalPropertySetIterator * iter)
{
return iter->cur_prop->type;
}
/**
* libhal_psi_get_key:
* @iter: iterator object
*
* Get the key of a property.
*
* Returns: ASCII nul-terminated string. This pointer is only valid
* until libhal_free_property_set() is invoked on the property set
* this property belongs to.
*/
char *
libhal_psi_get_key (LibHalPropertySetIterator * iter)
{
return iter->cur_prop->key;
}
/**
* libhal_psi_get_string:
* @iter: iterator object
*
* Get the value of a property of type string.
*
* Returns: UTF8 nul-terminated string. This pointer is only valid
* until libhal_free_property_set() is invoked on the property set
* this property belongs to.
*/
char *
libhal_psi_get_string (LibHalPropertySetIterator * iter)
{
return iter->cur_prop->v.str_value;
}
/**
* libhal_psi_get_int:
* @iter: iterator object
*
* Get the value of a property of type signed integer.
*
* Returns: property value (32-bit signed integer)
*/
dbus_int32_t
libhal_psi_get_int (LibHalPropertySetIterator * iter)
{
return iter->cur_prop->v.int_value;
}
/**
* libhal_psi_get_uint64:
* @iter: iterator object
*
* Get the value of a property of type unsigned integer.
*
* Returns: property value (64-bit unsigned integer)
*/
dbus_uint64_t
libhal_psi_get_uint64 (LibHalPropertySetIterator * iter)
{
return iter->cur_prop->v.uint64_value;
}
/**
* libhal_psi_get_double:
* @iter: iterator object
*
* Get the value of a property of type double.
*
* Returns: property value (IEEE754 double precision float)
*/
double
libhal_psi_get_double (LibHalPropertySetIterator * iter)
{
return iter->cur_prop->v.double_value;
}
/**
* libhal_psi_get_bool:
* @iter: iterator object
*
* Get the value of a property of type bool.
*
* Returns: property value (bool)
*/
dbus_bool_t
libhal_psi_get_bool (LibHalPropertySetIterator * iter)
{
return iter->cur_prop->v.bool_value;
}
/**
* libhal_psi_get_strlist:
* @iter: iterator object
*
* Get the value of a property of type string list.
*
* Returns: pointer to array of strings
*/
char **
libhal_psi_get_strlist (LibHalPropertySetIterator * iter)
{
return iter->cur_prop->v.strlist_value;
}
static DBusHandlerResult
filter_func (DBusConnection * connection,
DBusMessage * message, void *user_data)
{
const char *object_path;
DBusError error;
LibHalContext *ctx = (LibHalContext *) user_data;
if (ctx->is_shutdown)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
dbus_error_init (&error);
object_path = dbus_message_get_path (message);
/*printf("*** in filter_func, object_path=%s\n", object_path);*/
if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager",
"DeviceAdded")) {
char *udi;
if (dbus_message_get_args (message, &error,
DBUS_TYPE_STRING, &udi,
DBUS_TYPE_INVALID)) {
if (ctx->device_added != NULL) {
ctx->device_added (ctx, udi);
}
} else {
LIBHAL_FREE_DBUS_ERROR(&error);
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
} else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager", "DeviceRemoved")) {
char *udi;
if (dbus_message_get_args (message, &error,
DBUS_TYPE_STRING, &udi,
DBUS_TYPE_INVALID)) {
if (ctx->device_removed != NULL) {
ctx->device_removed (ctx, udi);
}
} else {
LIBHAL_FREE_DBUS_ERROR(&error);
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
} else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Manager","NewCapability")) {
char *udi;
char *capability;
if (dbus_message_get_args (message, &error,
DBUS_TYPE_STRING, &udi,
DBUS_TYPE_STRING, &capability,
DBUS_TYPE_INVALID)) {
if (ctx->device_new_capability != NULL) {
ctx->device_new_capability (ctx, udi, capability);
}
} else {
LIBHAL_FREE_DBUS_ERROR(&error);
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
} else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Device", "Condition")) {
char *condition_name;
char *condition_detail;
if (dbus_message_get_args (message, &error,
DBUS_TYPE_STRING, &condition_name,
DBUS_TYPE_STRING, &condition_detail,
DBUS_TYPE_INVALID)) {
if (ctx->device_condition != NULL) {
ctx->device_condition (ctx, object_path, condition_name, condition_detail);
}
} else {
LIBHAL_FREE_DBUS_ERROR(&error);
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
} else if (dbus_message_is_signal (message, "org.freedesktop.Hal.Device", "PropertyModified")) {
if (ctx->device_property_modified != NULL) {
int i;
char *key;
dbus_bool_t removed;
dbus_bool_t added;
int num_modifications;
DBusMessageIter iter;
DBusMessageIter iter_array;
dbus_message_iter_init (message, &iter);
dbus_message_iter_get_basic (&iter, &num_modifications);
dbus_message_iter_next (&iter);
dbus_message_iter_recurse (&iter, &iter_array);
for (i = 0; i < num_modifications; i++) {
DBusMessageIter iter_struct;
dbus_message_iter_recurse (&iter_array, &iter_struct);
dbus_message_iter_get_basic (&iter_struct, &key);
dbus_message_iter_next (&iter_struct);
dbus_message_iter_get_basic (&iter_struct, &removed);
dbus_message_iter_next (&iter_struct);
dbus_message_iter_get_basic (&iter_struct, &added);
ctx->device_property_modified (ctx,
object_path,
key, removed,
added);
dbus_message_iter_next (&iter_array);
}
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
/* for i18n purposes */
static dbus_bool_t libhal_already_initialized_once = FALSE;
/**
* libhal_get_all_devices:
* @ctx: the context for the connection to hald
* @num_devices: the number of devices will be stored here
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Get all devices in the Global Device List (GDL).
*
* Returns: An array of device identifiers terminated with NULL. It is
* the responsibility of the caller to free with
* libhal_free_string_array(). If an error occurs NULL is returned.
*/
char **
libhal_get_all_devices (LibHalContext *ctx, int *num_devices, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter_array, reply_iter;
char **hal_device_names;
DBusError _error;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
*num_devices = 0;
message = dbus_message_new_method_call ("org.freedesktop.Hal",
"/org/freedesktop/Hal/Manager",
"org.freedesktop.Hal.Manager",
"GetAllDevices");
if (message == NULL) {
fprintf (stderr, "%s %d : Could not allocate D-BUS message\n", __FILE__, __LINE__);
return NULL;
}
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection, message, -1, &_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return NULL;
}
if (reply == NULL) {
dbus_message_unref (message);
return NULL;
}
/* now analyze reply */
dbus_message_iter_init (reply, &reply_iter);
if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) {
fprintf (stderr, "%s %d : wrong reply from hald. Expecting an array.\n", __FILE__, __LINE__);
return NULL;
}
dbus_message_iter_recurse (&reply_iter, &iter_array);
hal_device_names = libhal_get_string_array_from_iter (&iter_array, num_devices);
dbus_message_unref (reply);
dbus_message_unref (message);
return hal_device_names;
}
/**
* libhal_device_get_property_type:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Query a property type of a device.
*
* Returns: A LibHalPropertyType. LIBHAL_PROPERTY_TYPE_INVALID is
* return if the property doesn't exist.
*/
LibHalPropertyType
libhal_device_get_property_type (LibHalContext *ctx, const char *udi, const char *key, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter, reply_iter;
int type;
DBusError _error;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, LIBHAL_PROPERTY_TYPE_INVALID); /* or return NULL? */
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"GetPropertyType");
if (message == NULL) {
fprintf (stderr, "%s %d : Couldn't allocate D-BUS message\n", __FILE__, __LINE__);
return LIBHAL_PROPERTY_TYPE_INVALID;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
&_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return LIBHAL_PROPERTY_TYPE_INVALID;
}
if (reply == NULL) {
dbus_message_unref (message);
return LIBHAL_PROPERTY_TYPE_INVALID;
}
dbus_message_iter_init (reply, &reply_iter);
dbus_message_iter_get_basic (&reply_iter, &type);
dbus_message_unref (message);
dbus_message_unref (reply);
return type;
}
/**
* libhal_device_get_property_strlist:
* @ctx: the context for the connection to hald
* @udi: unique Device Id
* @key: name of the property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Get the value of a property of type string list.
*
* Returns: Array of pointers to UTF8 nul-terminated strings
* terminated by NULL. The caller is responsible for freeing this
* string array with the function libhal_free_string_array(). Returns
* NULL if the property didn't exist or we are OOM
*/
char **
libhal_device_get_property_strlist (LibHalContext *ctx, const char *udi, const char *key, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter, iter_array, reply_iter;
char **our_strings;
DBusError _error;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"GetPropertyStringList");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return NULL;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
&_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return NULL;
}
if (reply == NULL) {
dbus_message_unref (message);
return NULL;
}
/* now analyse reply */
dbus_message_iter_init (reply, &reply_iter);
if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) {
fprintf (stderr, "%s %d : wrong reply from hald. Expecting an array.\n", __FILE__, __LINE__);
return NULL;
}
dbus_message_iter_recurse (&reply_iter, &iter_array);
our_strings = libhal_get_string_array_from_iter (&iter_array, NULL);
dbus_message_unref (reply);
dbus_message_unref (message);
return our_strings;
}
/**
* libhal_device_get_property_string:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: the name of the property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Get the value of a property of type string.
*
* Returns: UTF8 nul-terminated string. The caller is responsible for
* freeing this string with the function libhal_free_string(). Returns
* NULL if the property didn't exist or we are OOM.
*/
char *
libhal_device_get_property_string (LibHalContext *ctx,
const char *udi, const char *key, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter, reply_iter;
char *value;
char *dbus_str;
DBusError _error;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"GetPropertyString");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return NULL;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
&_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return NULL;
}
if (reply == NULL) {
dbus_message_unref (message);
return NULL;
}
dbus_message_iter_init (reply, &reply_iter);
/* now analyze reply */
if (dbus_message_iter_get_arg_type (&reply_iter) !=
DBUS_TYPE_STRING) {
dbus_message_unref (message);
dbus_message_unref (reply);
return NULL;
}
dbus_message_iter_get_basic (&reply_iter, &dbus_str);
value = (char *) ((dbus_str != NULL) ? strdup (dbus_str) : NULL);
if (value == NULL) {
fprintf (stderr, "%s %d : error allocating memory\n",
__FILE__, __LINE__);
/** @todo FIXME cleanup */
return NULL;
}
dbus_message_unref (message);
dbus_message_unref (reply);
return value;
}
/**
* libhal_device_get_property_int:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Get the value of a property of type integer.
*
* Returns: Property value (32-bit signed integer)
*/
dbus_int32_t
libhal_device_get_property_int (LibHalContext *ctx,
const char *udi, const char *key, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter, reply_iter;
dbus_int32_t value;
DBusError _error;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, -1);
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"GetPropertyInteger");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return -1;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
&_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return -1;
}
if (reply == NULL) {
dbus_message_unref (message);
return -1;
}
dbus_message_iter_init (reply, &reply_iter);
/* now analyze reply */
if (dbus_message_iter_get_arg_type (&reply_iter) !=
DBUS_TYPE_INT32) {
fprintf (stderr,
"%s %d : property '%s' for device '%s' is not "
"of type integer\n", __FILE__, __LINE__, key,
udi);
dbus_message_unref (message);
dbus_message_unref (reply);
return -1;
}
dbus_message_iter_get_basic (&reply_iter, &value);
dbus_message_unref (message);
dbus_message_unref (reply);
return value;
}
/**
* libhal_device_get_property_uint64:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Get the value of a property of type signed integer.
*
* Returns: Property value (64-bit unsigned integer)
*/
dbus_uint64_t
libhal_device_get_property_uint64 (LibHalContext *ctx,
const char *udi, const char *key, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter, reply_iter;
dbus_uint64_t value;
DBusError _error;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, -1);
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"GetPropertyInteger");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return -1;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
&_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return -1;
}
if (reply == NULL) {
dbus_message_unref (message);
return -1;
}
dbus_message_iter_init (reply, &reply_iter);
/* now analyze reply */
if (dbus_message_iter_get_arg_type (&reply_iter) !=
DBUS_TYPE_UINT64) {
fprintf (stderr,
"%s %d : property '%s' for device '%s' is not "
"of type integer\n", __FILE__, __LINE__, key,
udi);
dbus_message_unref (message);
dbus_message_unref (reply);
return -1;
}
dbus_message_iter_get_basic (&reply_iter, &value);
dbus_message_unref (message);
dbus_message_unref (reply);
return value;
}
/**
* libhal_device_get_property_double:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Get the value of a property of type double.
*
* Returns: Property value (IEEE754 double precision float)
*/
double
libhal_device_get_property_double (LibHalContext *ctx,
const char *udi, const char *key, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter, reply_iter;
double value;
DBusError _error;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, -1.0);
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"GetPropertyDouble");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return -1.0f;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
&_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return -1.0f;
}
if (reply == NULL) {
dbus_message_unref (message);
return -1.0f;
}
dbus_message_iter_init (reply, &reply_iter);
/* now analyze reply */
if (dbus_message_iter_get_arg_type (&reply_iter) !=
DBUS_TYPE_DOUBLE) {
fprintf (stderr,
"%s %d : property '%s' for device '%s' is not "
"of type double\n", __FILE__, __LINE__, key, udi);
dbus_message_unref (message);
dbus_message_unref (reply);
return -1.0f;
}
dbus_message_iter_get_basic (&reply_iter, &value);
dbus_message_unref (message);
dbus_message_unref (reply);
return (double) value;
}
/**
* libhal_device_get_property_bool:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Get the value of a property of type bool.
*
* Returns: Property value (boolean)
*/
dbus_bool_t
libhal_device_get_property_bool (LibHalContext *ctx,
const char *udi, const char *key, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter, reply_iter;
dbus_bool_t value;
DBusError _error;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"GetPropertyBoolean");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
&_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
if (reply == NULL) {
dbus_message_unref (message);
return FALSE;
}
dbus_message_iter_init (reply, &reply_iter);
/* now analyze reply */
if (dbus_message_iter_get_arg_type (&reply_iter) !=
DBUS_TYPE_BOOLEAN) {
fprintf (stderr,
"%s %d : property '%s' for device '%s' is not "
"of type bool\n", __FILE__, __LINE__, key, udi);
dbus_message_unref (message);
dbus_message_unref (reply);
return FALSE;
}
dbus_message_iter_get_basic (&reply_iter, &value);
dbus_message_unref (message);
dbus_message_unref (reply);
return value;
}
/* generic helper */
static dbus_bool_t
libhal_device_set_property_helper (LibHalContext *ctx,
const char *udi,
const char *key,
int type,
const char *str_value,
dbus_int32_t int_value,
dbus_uint64_t uint64_value,
double double_value,
dbus_bool_t bool_value,
DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter;
char *method_name = NULL;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
/** @todo sanity check incoming params */
switch (type) {
case DBUS_TYPE_INVALID:
method_name = "RemoveProperty";
break;
case DBUS_TYPE_STRING:
method_name = "SetPropertyString";
break;
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT64:
method_name = "SetPropertyInteger";
break;
case DBUS_TYPE_DOUBLE:
method_name = "SetPropertyDouble";
break;
case DBUS_TYPE_BOOLEAN:
method_name = "SetPropertyBoolean";
break;
default:
/* cannot happen; is not callable from outside this file */
break;
}
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
method_name);
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
switch (type) {
case DBUS_TYPE_STRING:
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &str_value);
break;
case DBUS_TYPE_INT32:
dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &int_value);
break;
case DBUS_TYPE_UINT64:
dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT64, &uint64_value);
break;
case DBUS_TYPE_DOUBLE:
dbus_message_iter_append_basic (&iter, DBUS_TYPE_DOUBLE, &double_value);
break;
case DBUS_TYPE_BOOLEAN:
dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &bool_value);
break;
}
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
if (reply == NULL) {
dbus_message_unref (message);
return FALSE;
}
dbus_message_unref (message);
dbus_message_unref (reply);
return TRUE;
}
/**
* libhal_device_set_property_string:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @value: value of the property; a UTF8 string
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Set a property of type string.
*
* Returns: TRUE if the property was set, FALSE if the device didn't
* exist or the property had a different type.
*/
dbus_bool_t
libhal_device_set_property_string (LibHalContext *ctx,
const char *udi,
const char *key,
const char *value,
DBusError *error)
{
return libhal_device_set_property_helper (ctx, udi, key,
DBUS_TYPE_STRING,
value, 0, 0, 0.0f, FALSE, error);
}
/**
* libhal_device_set_property_int:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @value: value of the property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Set a property of type signed integer.
*
* Returns: TRUE if the property was set, FALSE if the device didn't
* exist or the property had a different type.
*/
dbus_bool_t
libhal_device_set_property_int (LibHalContext *ctx, const char *udi,
const char *key, dbus_int32_t value, DBusError *error)
{
return libhal_device_set_property_helper (ctx, udi, key,
DBUS_TYPE_INT32,
NULL, value, 0, 0.0f, FALSE, error);
}
/**
* libhal_device_set_property_uint64:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @value: value of the property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Set a property of type unsigned integer.
*
* Returns: TRUE if the property was set, FALSE if the device didn't
* exist or the property had a different type.
*/
dbus_bool_t
libhal_device_set_property_uint64 (LibHalContext *ctx, const char *udi,
const char *key, dbus_uint64_t value, DBusError *error)
{
return libhal_device_set_property_helper (ctx, udi, key,
DBUS_TYPE_UINT64,
NULL, 0, value, 0.0f, FALSE, error);
}
/**
* libhal_device_set_property_double:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @value: value of the property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Set a property of type double.
*
* Returns: TRUE if the property was set, FALSE if the device didn't
* exist or the property had a different type.
*/
dbus_bool_t
libhal_device_set_property_double (LibHalContext *ctx, const char *udi,
const char *key, double value, DBusError *error)
{
return libhal_device_set_property_helper (ctx, udi, key,
DBUS_TYPE_DOUBLE,
NULL, 0, 0, value, FALSE, error);
}
/**
* libhal_device_set_property_bool:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @value: value of the property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Set a property of type bool.
*
* Returns: TRUE if the property was set, FALSE if the device didn't
* exist or the property had a different type.
*/
dbus_bool_t
libhal_device_set_property_bool (LibHalContext *ctx, const char *udi,
const char *key, dbus_bool_t value, DBusError *error)
{
return libhal_device_set_property_helper (ctx, udi, key,
DBUS_TYPE_BOOLEAN,
NULL, 0, 0, 0.0f, value, error);
}
/**
* libhal_device_remove_property:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Remove a property.
*
* Returns: TRUE if the property was set, FALSE if the device didn't
* exist
*/
dbus_bool_t
libhal_device_remove_property (LibHalContext *ctx,
const char *udi, const char *key, DBusError *error)
{
return libhal_device_set_property_helper (ctx, udi, key, DBUS_TYPE_INVALID,
/* DBUS_TYPE_INVALID means remove */
NULL, 0, 0, 0.0f, FALSE, error);
}
/**
* libhal_device_property_strlist_append:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @value: value to append to property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Append to a property of type strlist.
*
* Returns: TRUE if the value was appended, FALSE if the device didn't
* exist or the property had a different type.
*/
dbus_bool_t
libhal_device_property_strlist_append (LibHalContext *ctx,
const char *udi,
const char *key,
const char *value,
DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"StringListAppend");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
if (reply == NULL) {
dbus_message_unref (message);
return FALSE;
}
return TRUE;
}
/**
* libhal_device_property_strlist_prepend:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @value: value to prepend to property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Prepend to a property of type strlist.
*
* Returns: TRUE if the value was prepended, FALSE if the device
* didn't exist or the property had a different type.
*/
dbus_bool_t
libhal_device_property_strlist_prepend (LibHalContext *ctx,
const char *udi,
const char *key,
const char *value,
DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"StringListPrepend");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
if (reply == NULL) {
dbus_message_unref (message);
return FALSE;
}
return TRUE;
}
/**
* libhal_device_property_strlist_remove_index:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @idx: index of string to remove in the strlist
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Remove a specified string from a property of type strlist.
*
* Returns: TRUE if the string was removed, FALSE if the device didn't
* exist or the property had a different type.
*/
dbus_bool_t
libhal_device_property_strlist_remove_index (LibHalContext *ctx,
const char *udi,
const char *key,
unsigned int idx,
DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"StringListRemoveIndex");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &idx);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
if (reply == NULL) {
dbus_message_unref (message);
return FALSE;
}
return TRUE;
}
/**
* libhal_device_property_strlist_remove:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @key: name of the property
* @value: the string to remove
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Remove a specified string from a property of type strlist.
*
* Returns: TRUE if the string was removed, FALSE if the device didn't
* exist or the property had a different type.
*/
dbus_bool_t
libhal_device_property_strlist_remove (LibHalContext *ctx,
const char *udi,
const char *key,
const char *value, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"StringListRemove");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
if (reply == NULL) {
dbus_message_unref (message);
return FALSE;
}
return TRUE;
}
/**
* libhal_device_lock:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @reason_to_lock: a user-presentable reason why the device is locked.
* @reason_why_locked: a pointer to store the reason why the device cannot be locked on failure, or NULL
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Take an advisory lock on the device.
*
* Returns: TRUE if the lock was obtained, FALSE otherwise
*/
dbus_bool_t
libhal_device_lock (LibHalContext *ctx,
const char *udi,
const char *reason_to_lock,
char **reason_why_locked, DBusError *error)
{
DBusMessage *message;
DBusMessageIter iter;
DBusMessage *reply;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
if (reason_why_locked != NULL)
*reason_why_locked = NULL;
message = dbus_message_new_method_call ("org.freedesktop.Hal",
udi,
"org.freedesktop.Hal.Device",
"Lock");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &reason_to_lock);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
if (strcmp (error->name,
"org.freedesktop.Hal.DeviceAlreadyLocked") == 0) {
if (reason_why_locked != NULL) {
*reason_why_locked =
dbus_malloc0 (strlen (error->message) + 1);
strcpy (*reason_why_locked, error->message);
}
}
dbus_message_unref (message);
return FALSE;
}
dbus_message_unref (message);
if (reply == NULL)
return FALSE;
dbus_message_unref (reply);
return TRUE;
}
/**
* libhal_device_unlock:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Release an advisory lock on the device.
*
* Returns: TRUE if the device was successfully unlocked,
* FALSE otherwise
*/
dbus_bool_t
libhal_device_unlock (LibHalContext *ctx,
const char *udi, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal",
udi,
"org.freedesktop.Hal.Device",
"Unlock");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
dbus_message_unref (message);
if (reply == NULL)
return FALSE;
dbus_message_unref (reply);
return TRUE;
}
/**
* libhal_new_device:
* @ctx: the context for the connection to hald
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Create a new device object which will be hidden from applications
* until the CommitToGdl(), ie. libhal_device_commit_to_gdl(), method
* is called. Note that the program invoking this method needs to run
* with super user privileges.
*
* Returns: Temporary device unique id or NULL if there was a
* problem. This string must be freed by the caller.
*/
char *
libhal_new_device (LibHalContext *ctx, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter reply_iter;
char *value;
char *dbus_str;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
message = dbus_message_new_method_call ("org.freedesktop.Hal",
"/org/freedesktop/Hal/Manager",
"org.freedesktop.Hal.Manager",
"NewDevice");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return NULL;
}
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return NULL;
}
if (reply == NULL) {
dbus_message_unref (message);
return NULL;
}
dbus_message_iter_init (reply, &reply_iter);
/* now analyze reply */
if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_STRING) {
fprintf (stderr,
"%s %d : expected a string in reply to NewDevice\n",
__FILE__, __LINE__);
dbus_message_unref (message);
dbus_message_unref (reply);
return NULL;
}
dbus_message_iter_get_basic (&reply_iter, &dbus_str);
value = (char *) ((dbus_str != NULL) ? strdup (dbus_str) : NULL);
if (value == NULL) {
fprintf (stderr, "%s %d : error allocating memory\n",
__FILE__, __LINE__);
}
dbus_message_unref (message);
dbus_message_unref (reply);
return value;
}
/**
* libhal_device_commit_to_gdl:
* @ctx: the context for the connection to hald
* @temp_udi: the temporary unique device id as returned by libhal_new_device()
* @udi: the new unique device id.
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* When a hidden device has been built using the NewDevice method,
* ie. libhal_new_device(), and the org.freedesktop.Hal.Device
* interface this function will commit it to the global device list.
*
* This means that the device object will be visible to applications
* and the HAL daemon will possibly attempt to boot the device
* (depending on the property RequireEnable).
*
* Note that the program invoking this method needs to run with super
* user privileges.
*
* Returns: FALSE if the given unique device id is already in use.
*/
dbus_bool_t
libhal_device_commit_to_gdl (LibHalContext *ctx,
const char *temp_udi, const char *udi, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal",
"/org/freedesktop/Hal/Manager",
"org.freedesktop.Hal.Manager",
"CommitToGdl");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &temp_udi);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
if (reply == NULL) {
dbus_message_unref (message);
return FALSE;
}
dbus_message_unref (message);
dbus_message_unref (reply);
return TRUE;
}
/**
* libhal_remove_device:
* @ctx: the context for the connection to hald
* @udi: the Unique device id.
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* This method can be invoked when a device is removed. The HAL daemon
* will shut down the device. Note that the device may still be in the
* device list if the Persistent property is set to true.
*
* Note that the program invoking this method needs to run with super
* user privileges.
*
* Returns: TRUE if the device was removed, FALSE otherwise
*/
dbus_bool_t
libhal_remove_device (LibHalContext *ctx, const char *udi, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal",
"/org/freedesktop/Hal/Manager",
"org.freedesktop.Hal.Manager",
"Remove");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
if (reply == NULL) {
dbus_message_unref (message);
return FALSE;
}
dbus_message_unref (message);
dbus_message_unref (reply);
return TRUE;
}
/**
* libhal_device_exists:
* @ctx: the context for the connection to hald
* @udi: the Unique device id.
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Determine if a device exists.
*
* Returns: TRUE if the device exists
*/
dbus_bool_t
libhal_device_exists (LibHalContext *ctx, const char *udi, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter, reply_iter;
dbus_bool_t value;
DBusError _error;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal",
"/org/freedesktop/Hal/Manager",
"org.freedesktop.Hal.Manager",
"DeviceExists");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
&_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
if (reply == NULL) {
dbus_message_unref (message);
return FALSE;
}
dbus_message_iter_init (reply, &reply_iter);
/* now analyze reply */
if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) {
fprintf (stderr,
"%s %d : expected a bool in reply to DeviceExists\n",
__FILE__, __LINE__);
dbus_message_unref (message);
dbus_message_unref (reply);
return FALSE;
}
dbus_message_iter_get_basic (&reply_iter, &value);
dbus_message_unref (message);
dbus_message_unref (reply);
return value;
}
/**
* libhal_device_property_exists:
* @ctx: the context for the connection to hald
* @udi: the Unique device id.
* @key: name of the property
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Determine if a property on a device exists.
*
* Returns: TRUE if the device exists, FALSE otherwise
*/
dbus_bool_t
libhal_device_property_exists (LibHalContext *ctx,
const char *udi, const char *key, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter, reply_iter;
dbus_bool_t value;
DBusError _error;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"PropertyExists");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
&_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
if (reply == NULL) {
dbus_message_unref (message);
return FALSE;
}
dbus_message_iter_init (reply, &reply_iter);
/* now analyse reply */
if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) {
fprintf (stderr, "%s %d : expected a bool in reply to "
"PropertyExists\n", __FILE__, __LINE__);
dbus_message_unref (message);
dbus_message_unref (reply);
return FALSE;
}
dbus_message_iter_get_basic (&reply_iter, &value);
dbus_message_unref (message);
dbus_message_unref (reply);
return value;
}
/**
* libhal_merge_properties:
* @ctx: the context for the connection to hald
* @target_udi: the Unique device id of target device to merge to
* @source_udi: the Unique device id of device to merge from
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Merge properties from one device to another.
*
* Returns: TRUE if the properties were merged, FALSE otherwise
*/
dbus_bool_t
libhal_merge_properties (LibHalContext *ctx,
const char *target_udi, const char *source_udi, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal",
"/org/freedesktop/Hal/Manager",
"org.freedesktop.Hal.Manager",
"MergeProperties");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &target_udi);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &source_udi);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
if (reply == NULL) {
dbus_message_unref (message);
return FALSE;
}
dbus_message_unref (message);
dbus_message_unref (reply);
return TRUE;
}
/**
* libhal_device_matches:
* @ctx: the context for the connection to hald
* @udi1: the Unique Device Id for device 1
* @udi2: the Unique Device Id for device 2
* @property_namespace: the namespace for set of devices, e.g. "usb"
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Check a set of properties for two devices matches.
*
* Checks that all properties where keys, starting with a given value
* (namespace), of the first device is in the second device and that
* they got the same value and type.
*
* Note that the other inclusion isn't tested, so there could be
* properties (from the given namespace) in the second device not
* present in the first device.
*
* Returns: TRUE if all properties starting with the given namespace
* parameter from one device is in the other and have the same value.
*/
dbus_bool_t
libhal_device_matches (LibHalContext *ctx,
const char *udi1, const char *udi2,
const char *property_namespace, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter, reply_iter;
dbus_bool_t value;
DBusError _error;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal",
"/org/freedesktop/Hal/Manager",
"org.freedesktop.Hal.Manager",
"DeviceMatches");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, udi1);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, udi2);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, property_namespace);
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
&_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
if (reply == NULL) {
dbus_message_unref (message);
return FALSE;
}
/* now analyse reply */
dbus_message_iter_init (reply, &reply_iter);
if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) {
fprintf (stderr,
"%s %d : expected a bool in reply to DeviceMatches\n",
__FILE__, __LINE__);
dbus_message_unref (message);
dbus_message_unref (reply);
return FALSE;
}
dbus_message_iter_get_basic (&reply_iter, &value);
dbus_message_unref (message);
dbus_message_unref (reply);
return value;
}
/**
* libhal_device_print:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Print a device to stdout; useful for debugging.
*
* Returns: TRUE if device's information could be obtained, FALSE otherwise
*/
dbus_bool_t
libhal_device_print (LibHalContext *ctx, const char *udi, DBusError *error)
{
int type;
char *key;
LibHalPropertySet *pset;
LibHalPropertySetIterator i;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
printf ("device_id = %s\n", udi);
if ((pset = libhal_device_get_all_properties (ctx, udi, error)) == NULL)
return FALSE;
for (libhal_psi_init (&i, pset); libhal_psi_has_more (&i);
libhal_psi_next (&i)) {
type = libhal_psi_get_type (&i);
key = libhal_psi_get_key (&i);
switch (type) {
case LIBHAL_PROPERTY_TYPE_STRING:
printf (" %s = '%s' (string)\n", key,
libhal_psi_get_string (&i));
break;
case LIBHAL_PROPERTY_TYPE_INT32:
printf (" %s = %d = 0x%x (int)\n", key,
libhal_psi_get_int (&i),
libhal_psi_get_int (&i));
break;
case LIBHAL_PROPERTY_TYPE_UINT64:
printf (" %s = %llu = 0x%llx (uint64)\n", key,
(long long unsigned int) libhal_psi_get_uint64 (&i),
(long long unsigned int) libhal_psi_get_uint64 (&i));
break;
case LIBHAL_PROPERTY_TYPE_BOOLEAN:
printf (" %s = %s (bool)\n", key,
(libhal_psi_get_bool (&i) ? "true" :
"false"));
break;
case LIBHAL_PROPERTY_TYPE_DOUBLE:
printf (" %s = %g (double)\n", key,
libhal_psi_get_double (&i));
break;
case LIBHAL_PROPERTY_TYPE_STRLIST:
{
unsigned int j;
char **str_list;
str_list = libhal_psi_get_strlist (&i);
printf (" %s = [", key);
for (j = 0; str_list[j] != NULL; j++) {
printf ("'%s'", str_list[j]);
if (str_list[j+1] != NULL)
printf (", ");
}
printf ("] (string list)\n");
break;
}
default:
printf (" *** unknown type for key %s\n", key);
break;
}
}
libhal_free_property_set (pset);
return TRUE;
}
/**
* libhal_manager_find_device_string_match:
* @ctx: the context for the connection to hald
* @key: name of the property
* @value: the value to match
* @num_devices: pointer to store number of devices
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Find a device in the GDL where a single string property matches a
* given value.
*
* Returns: UDI of devices; free with libhal_free_string_array()
*/
char **
libhal_manager_find_device_string_match (LibHalContext *ctx,
const char *key,
const char *value, int *num_devices, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter, iter_array, reply_iter;
char **hal_device_names;
DBusError _error;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
message = dbus_message_new_method_call ("org.freedesktop.Hal",
"/org/freedesktop/Hal/Manager",
"org.freedesktop.Hal.Manager",
"FindDeviceStringMatch");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return NULL;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value);
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
&_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return NULL;
}
if (reply == NULL) {
dbus_message_unref (message);
return NULL;
}
/* now analyse reply */
dbus_message_iter_init (reply, &reply_iter);
if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) {
fprintf (stderr, "%s %d : wrong reply from hald. Expecting an array.\n", __FILE__, __LINE__);
return NULL;
}
dbus_message_iter_recurse (&reply_iter, &iter_array);
hal_device_names = libhal_get_string_array_from_iter (&iter_array, num_devices);
dbus_message_unref (reply);
dbus_message_unref (message);
return hal_device_names;
}
/**
* libhal_device_add_capability:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @capability: the capability name to add
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Assign a capability to a device.
*
* Returns: TRUE if the capability was added, FALSE if the device didn't exist
*/
dbus_bool_t
libhal_device_add_capability (LibHalContext *ctx,
const char *udi, const char *capability, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"AddCapability");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &capability);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
if (reply == NULL) {
dbus_message_unref (message);
return FALSE;
}
dbus_message_unref (reply);
dbus_message_unref (message);
return TRUE;
}
/**
* libhal_device_query_capability:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @capability: the capability name
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Check if a device has a capability. The result is undefined if the
* device doesn't exist.
*
* Returns: TRUE if the device has the capability, otherwise FALSE
*/
dbus_bool_t
libhal_device_query_capability (LibHalContext *ctx, const char *udi, const char *capability, DBusError *error)
{
char **caps;
unsigned int i;
dbus_bool_t ret;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
ret = FALSE;
caps = libhal_device_get_property_strlist (ctx, udi, "info.capabilities", error);
if (caps != NULL) {
for (i = 0; caps[i] != NULL; i++) {
if (strcmp (caps[i], capability) == 0) {
ret = TRUE;
break;
}
}
libhal_free_string_array (caps);
}
return ret;
}
/**
* libhal_find_device_by_capability:
* @ctx: the context for the connection to hald
* @capability: the capability name
* @num_devices: pointer to store number of devices
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Find devices with a given capability.
*
* Returns: UDI of devices; free with libhal_free_string_array()
*/
char **
libhal_find_device_by_capability (LibHalContext *ctx,
const char *capability, int *num_devices, DBusError *error)
{
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter, iter_array, reply_iter;
char **hal_device_names;
DBusError _error;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, NULL);
message = dbus_message_new_method_call ("org.freedesktop.Hal",
"/org/freedesktop/Hal/Manager",
"org.freedesktop.Hal.Manager",
"FindDeviceByCapability");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return NULL;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &capability);
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
&_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return NULL;
}
if (reply == NULL) {
dbus_message_unref (message);
return NULL;
}
/* now analyse reply */
dbus_message_iter_init (reply, &reply_iter);
if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_ARRAY) {
fprintf (stderr, "%s %d : wrong reply from hald. Expecting an array.\n", __FILE__, __LINE__);
return NULL;
}
dbus_message_iter_recurse (&reply_iter, &iter_array);
hal_device_names = libhal_get_string_array_from_iter (&iter_array, num_devices);
dbus_message_unref (reply);
dbus_message_unref (message);
return hal_device_names;
}
/**
* libhal_device_property_watch_all:
* @ctx: the context for the connection to hald
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Watch all devices, ie. the device_property_changed callback is
* invoked when the properties on any device changes.
*
* Returns: TRUE only if the operation succeeded
*/
dbus_bool_t
libhal_device_property_watch_all (LibHalContext *ctx, DBusError *error)
{
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
dbus_bus_add_match (ctx->connection,
"type='signal',"
"interface='org.freedesktop.Hal.Device',"
"sender='org.freedesktop.Hal'", error);
if (error != NULL && dbus_error_is_set (error)) {
return FALSE;
}
return TRUE;
}
/**
* libhal_device_add_property_watch:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Add a watch on a device, so the device_property_changed callback is
* invoked when the properties on the given device changes.
*
* The application itself is responsible for deleting the watch, using
* libhal_device_remove_property_watch, if the device is removed.
*
* Returns: TRUE only if the operation succeeded
*/
dbus_bool_t
libhal_device_add_property_watch (LibHalContext *ctx, const char *udi, DBusError *error)
{
char buf[512];
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
snprintf (buf, 512,
"type='signal',"
"interface='org.freedesktop.Hal.Device',"
"sender='org.freedesktop.Hal'," "path=%s", udi);
dbus_bus_add_match (ctx->connection, buf, error);
if (error != NULL && dbus_error_is_set (error)) {
return FALSE;
}
return TRUE;
}
/**
* libhal_device_remove_property_watch:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Remove a watch on a device.
*
* Returns: TRUE only if the operation succeeded
*/
dbus_bool_t
libhal_device_remove_property_watch (LibHalContext *ctx, const char *udi, DBusError *error)
{
char buf[512];
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
snprintf (buf, 512,
"type='signal',"
"interface='org.freedesktop.Hal.Device',"
"sender='org.freedesktop.Hal'," "path=%s", udi);
dbus_bus_remove_match (ctx->connection, buf, error);
if (error != NULL && dbus_error_is_set (error)) {
return FALSE;
}
return TRUE;
}
/**
* libhal_ctx_new:
*
* Create a new LibHalContext
*
* Returns: a new uninitialized LibHalContext object
*/
LibHalContext *
libhal_ctx_new (void)
{
LibHalContext *ctx;
if (!libhal_already_initialized_once) {
bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
libhal_already_initialized_once = TRUE;
}
ctx = calloc (1, sizeof (LibHalContext));
if (ctx == NULL) {
fprintf (stderr,
"%s %d : Failed to allocate %d bytes\n",
__FILE__, __LINE__, sizeof (LibHalContext));
return NULL;
}
ctx->is_initialized = FALSE;
ctx->is_shutdown = FALSE;
ctx->connection = NULL;
ctx->is_direct = FALSE;
return ctx;
}
/**
* libhal_ctx_set_cache:
* @ctx: context to enable/disable cache for
* @use_cache: whether or not to use cache
*
* Enable or disable caching. Note: Caching is not actually
* implemented yet.
*
* Returns: TRUE if cache was successfully enabled/disabled, FALSE otherwise
*/
dbus_bool_t
libhal_ctx_set_cache (LibHalContext *ctx, dbus_bool_t use_cache)
{
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
ctx->cache_enabled = use_cache;
return TRUE;
}
/**
* libhal_ctx_set_dbus_connection:
* @ctx: context to set connection for
* @conn: DBus connection to use
*
* Set DBus connection to use to talk to hald.
*
* Returns: TRUE if connection was successfully set, FALSE otherwise
*/
dbus_bool_t
libhal_ctx_set_dbus_connection (LibHalContext *ctx, DBusConnection *conn)
{
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
if (conn == NULL)
return FALSE;
ctx->connection = conn;
return TRUE;
}
/**
* libhal_ctx_get_dbus_connection:
* @ctx: context to get connection for
*
* Get DBus connection used for talking to hald.
*
* Returns: DBus connection to use or NULL
*/
DBusConnection *
libhal_ctx_get_dbus_connection (LibHalContext *ctx)
{
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
return ctx->connection;
}
/**
* libhal_ctx_init:
* @ctx: Context for connection to hald (D-BUS connection should be set with libhal_ctx_set_dbus_connection)
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Initialize the connection to hald.
*
* Returns: TRUE if initialization succeeds, FALSE otherwise
*/
dbus_bool_t
libhal_ctx_init (LibHalContext *ctx, DBusError *error)
{
DBusError _error;
dbus_bool_t hald_exists;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
if (ctx->connection == NULL)
return FALSE;
dbus_error_init (&_error);
hald_exists = dbus_bus_name_has_owner (ctx->connection, "org.freedesktop.Hal", &_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
return FALSE;
}
if (!hald_exists) {
return FALSE;
}
if (!dbus_connection_add_filter (ctx->connection, filter_func, ctx, NULL)) {
return FALSE;
}
dbus_bus_add_match (ctx->connection,
"type='signal',"
"interface='org.freedesktop.Hal.Manager',"
"sender='org.freedesktop.Hal',"
"path='/org/freedesktop/Hal/Manager'", &_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
return FALSE;
}
ctx->is_initialized = TRUE;
ctx->is_direct = FALSE;
return TRUE;
}
/**
* libhal_ctx_init_direct:
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Create an already initialized connection to hald. This function should only be used by HAL helpers.
*
* Returns: A pointer to an already initialized LibHalContext
*/
LibHalContext *
libhal_ctx_init_direct (DBusError *error)
{
char *hald_addr;
LibHalContext *ctx;
DBusError _error;
ctx = libhal_ctx_new ();
if (ctx == NULL)
goto out;
if (((hald_addr = getenv ("HALD_DIRECT_ADDR"))) == NULL) {
libhal_ctx_free (ctx);
ctx = NULL;
goto out;
}
dbus_error_init (&_error);
ctx->connection = dbus_connection_open (hald_addr, &_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
libhal_ctx_free (ctx);
ctx = NULL;
goto out;
}
ctx->is_initialized = TRUE;
ctx->is_direct = TRUE;
out:
return ctx;
}
/**
* libhal_ctx_shutdown:
* @ctx: the context for the connection to hald
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Shut down a connection to hald.
*
* Returns: TRUE if connection successfully shut down, FALSE otherwise
*/
dbus_bool_t
libhal_ctx_shutdown (LibHalContext *ctx, DBusError *error)
{
DBusError myerror;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
if (ctx->is_direct) {
/* for some reason dbus_connection_set_exit_on_disconnect doesn't work yet so don't unref */
/*dbus_connection_unref (ctx->connection);*/
} else {
dbus_error_init (&myerror);
dbus_bus_remove_match (ctx->connection,
"type='signal',"
"interface='org.freedesktop.Hal.Manager',"
"sender='org.freedesktop.Hal',"
"path='/org/freedesktop/Hal/Manager'", &myerror);
dbus_move_error(&myerror, error);
if (error != NULL && dbus_error_is_set(error)) {
fprintf (stderr, "%s %d : Error unsubscribing to signals, error=%s\n",
__FILE__, __LINE__, error->message);
/** @todo clean up */
}
/* TODO: remove other matches */
dbus_connection_remove_filter (ctx->connection, filter_func, ctx);
}
ctx->is_initialized = FALSE;
return TRUE;
}
/**
* libhal_ctx_free:
* @ctx: pointer to a LibHalContext
*
* Free a LibHalContext resource.
*
* Returns: TRUE
*/
dbus_bool_t
libhal_ctx_free (LibHalContext *ctx)
{
free (ctx);
return TRUE;
}
/**
* libhal_ctx_set_device_added:
* @ctx: the context for the connection to hald
* @callback: the function to call when a device is added
*
* Set the callback for when a device is added
*
* Returns: TRUE if callback was successfully set, FALSE otherwise
*/
dbus_bool_t
libhal_ctx_set_device_added (LibHalContext *ctx, LibHalDeviceAdded callback)
{
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
ctx->device_added = callback;
return TRUE;
}
/**
* libhal_ctx_set_device_removed:
* @ctx: the context for the connection to hald
* @callback: the function to call when a device is removed
*
* Set the callback for when a device is removed.
*
* Returns: TRUE if callback was successfully set, FALSE otherwise
*/
dbus_bool_t
libhal_ctx_set_device_removed (LibHalContext *ctx, LibHalDeviceRemoved callback)
{
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
ctx->device_removed = callback;
return TRUE;
}
/**
* libhal_ctx_set_device_new_capability:
* @ctx: the context for the connection to hald
* @callback: the function to call when a device gains a new capability
*
* Set the callback for when a device gains a new capability.
*
* Returns: TRUE if callback was successfully set, FALSE otherwise
*/
dbus_bool_t
libhal_ctx_set_device_new_capability (LibHalContext *ctx, LibHalDeviceNewCapability callback)
{
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
ctx->device_new_capability = callback;
return TRUE;
}
/**
* libhal_ctx_set_device_lost_capability:
* @ctx: the context for the connection to hald
* @callback: the function to call when a device loses a capability
*
* Set the callback for when a device loses a capability
*
* Returns: TRUE if callback was successfully set, FALSE otherwise
*/
dbus_bool_t
libhal_ctx_set_device_lost_capability (LibHalContext *ctx, LibHalDeviceLostCapability callback)
{
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
ctx->device_lost_capability = callback;
return TRUE;
}
/**
* libhal_ctx_set_device_property_modified:
* @ctx: the context for the connection to hald
* @callback: the function to call when a property is modified on a device
*
* Set the callback for when a property is modified on a device.
*
* Returns: TRUE if callback was successfully set, FALSE otherwise
*/
dbus_bool_t
libhal_ctx_set_device_property_modified (LibHalContext *ctx, LibHalDevicePropertyModified callback)
{
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
ctx->device_property_modified = callback;
return TRUE;
}
/**
* libhal_ctx_set_device_condition:
* @ctx: the context for the connection to hald
* @callback: the function to call when a device emits a condition
*
* Set the callback for when a device emits a condition
*
* Returns: TRUE if callback was successfully set, FALSE otherwise
*/
dbus_bool_t
libhal_ctx_set_device_condition (LibHalContext *ctx, LibHalDeviceCondition callback)
{
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
ctx->device_condition = callback;
return TRUE;
}
/**
* libhal_string_array_length:
* @str_array: array of strings to consider
*
* Get the length of an array of strings.
*
* Returns: Number of strings in array
*/
unsigned int
libhal_string_array_length (char **str_array)
{
unsigned int i;
if (str_array == NULL)
return 0;
for (i = 0; str_array[i] != NULL; i++)
;
return i;
}
/**
* libhal_device_rescan:
* @ctx: the context for the connection to hald
* @udi: the Unique id of device
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* TODO document me.
*
* Returns: Whether the operation succeeded
*/
dbus_bool_t
libhal_device_rescan (LibHalContext *ctx, const char *udi, DBusError *error)
{
DBusMessage *message;
DBusMessageIter reply_iter;
DBusMessage *reply;
dbus_bool_t result;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
"org.freedesktop.Hal.Device",
"Rescan");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
dbus_message_unref (message);
if (reply == NULL)
return FALSE;
dbus_message_iter_init (reply, &reply_iter);
if (dbus_message_iter_get_arg_type (&reply_iter) !=
DBUS_TYPE_BOOLEAN) {
dbus_message_unref (message);
dbus_message_unref (reply);
return FALSE;
}
dbus_message_iter_get_basic (&reply_iter, &result);
dbus_message_unref (reply);
return result;
}
/**
* libhal_device_reprobe:
* @ctx: the context for the connection to hald
* @udi: the Unique id of device
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* TODO document me.
*
* Returns: Whether the operation succeeded
*/
dbus_bool_t
libhal_device_reprobe (LibHalContext *ctx, const char *udi, DBusError *error)
{
DBusMessage *message;
DBusMessageIter reply_iter;
DBusMessage *reply;
dbus_bool_t result;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal",
udi,
"org.freedesktop.Hal.Device",
"Reprobe");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
dbus_message_unref (message);
if (reply == NULL)
return FALSE;
dbus_message_iter_init (reply, &reply_iter);
if (dbus_message_iter_get_arg_type (&reply_iter) !=
DBUS_TYPE_BOOLEAN) {
dbus_message_unref (message);
dbus_message_unref (reply);
return FALSE;
}
dbus_message_iter_get_basic (&reply_iter, &result);
dbus_message_unref (reply);
return result;
}
/**
* libhal_device_emit_condition:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @condition_name: user-readable name of condition
* @condition_details: user-readable details of condition
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Emit a condition from a device. Can only be used from hald helpers.
*
* Returns: TRUE if condition successfully emitted,
* FALSE otherwise
*/
dbus_bool_t libhal_device_emit_condition (LibHalContext *ctx,
const char *udi,
const char *condition_name,
const char *condition_details,
DBusError *error)
{
DBusMessage *message;
DBusMessageIter iter;
DBusMessageIter reply_iter;
DBusMessage *reply;
dbus_bool_t result;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal",
udi,
"org.freedesktop.Hal.Device",
"EmitCondition");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &condition_name);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &condition_details);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
dbus_message_unref (message);
if (reply == NULL)
return FALSE;
dbus_message_iter_init (reply, &reply_iter);
if (dbus_message_iter_get_arg_type (&reply_iter) !=
DBUS_TYPE_BOOLEAN) {
dbus_message_unref (message);
dbus_message_unref (reply);
return FALSE;
}
dbus_message_iter_get_basic (&reply_iter, &result);
dbus_message_unref (reply);
return result;
}
/**
* libhal_device_addon_is_ready:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* HAL addon's must call this method when they are done initializing the device object. The HAL
* daemon will wait for all addon's to call this.
*
* Can only be used from hald helpers.
*
* Returns: TRUE if the HAL daemon received the message, FALSE otherwise
*/
dbus_bool_t
libhal_device_addon_is_ready (LibHalContext *ctx, const char *udi, DBusError *error)
{
DBusMessage *message;
DBusMessageIter iter;
DBusMessageIter reply_iter;
DBusMessage *reply;
dbus_bool_t result;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal",
udi,
"org.freedesktop.Hal.Device",
"AddonIsReady");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
dbus_message_unref (message);
if (reply == NULL)
return FALSE;
dbus_message_iter_init (reply, &reply_iter);
if (dbus_message_iter_get_arg_type (&reply_iter) != DBUS_TYPE_BOOLEAN) {
dbus_message_unref (message);
dbus_message_unref (reply);
return FALSE;
}
dbus_message_iter_get_basic (&reply_iter, &result);
dbus_message_unref (reply);
return result;
}
/**
* libhal_device_claim_interface:
* @ctx: the context for the connection to hald
* @udi: the Unique Device Id
* @interface_name: Name of interface to claim, e.g. org.freedesktop.Hal.Device.FoobarKindOfThing
* @introspection_xml: Introspection XML containing what would be inside the interface XML tag
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Claim an interface for a device. All messages to this interface
* will be forwarded to the helper. Can only be used from hald
* helpers.
*
* Returns: TRUE if interface was claimed, FALSE otherwise
*/
dbus_bool_t
libhal_device_claim_interface (LibHalContext *ctx,
const char *udi,
const char *interface_name,
const char *introspection_xml,
DBusError *error)
{
DBusMessage *message;
DBusMessageIter iter;
DBusMessageIter reply_iter;
DBusMessage *reply;
dbus_bool_t result;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
message = dbus_message_new_method_call ("org.freedesktop.Hal",
udi,
"org.freedesktop.Hal.Device",
"ClaimInterface");
if (message == NULL) {
fprintf (stderr,
"%s %d : Couldn't allocate D-BUS message\n",
__FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &interface_name);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &introspection_xml);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
error);
if (error != NULL && dbus_error_is_set (error)) {
dbus_message_unref (message);
return FALSE;
}
dbus_message_unref (message);
if (reply == NULL)
return FALSE;
dbus_message_iter_init (reply, &reply_iter);
if (dbus_message_iter_get_arg_type (&reply_iter) !=
DBUS_TYPE_BOOLEAN) {
dbus_message_unref (message);
dbus_message_unref (reply);
return FALSE;
}
dbus_message_iter_get_basic (&reply_iter, &result);
dbus_message_unref (reply);
return result;
}
struct LibHalChangeSetElement_s;
typedef struct LibHalChangeSetElement_s LibHalChangeSetElement;
struct LibHalChangeSetElement_s {
char *key;
int change_type;
union {
char *val_str;
dbus_int32_t val_int;
dbus_uint64_t val_uint64;
double val_double;
dbus_bool_t val_bool;
char **val_strlist;
} value;
LibHalChangeSetElement *next;
LibHalChangeSetElement *prev;
};
struct LibHalChangeSet_s {
char *udi;
LibHalChangeSetElement *head;
LibHalChangeSetElement *tail;
};
/**
* libhal_device_new_changeset:
* @udi: unique device identifier
*
* Request a new changeset object. Used for changing multiple properties at once. Useful when
* performance is critical and also for atomically updating several properties.
*
* Returns: A new changeset object or NULL on error
*/
LibHalChangeSet *
libhal_device_new_changeset (const char *udi)
{
LibHalChangeSet *changeset;
changeset = calloc (1, sizeof (LibHalChangeSet));
if (changeset == NULL)
goto out;
changeset->udi = strdup (udi);
if (changeset->udi == NULL) {
free (changeset);
changeset = NULL;
goto out;
}
changeset->head = NULL;
changeset->tail = NULL;
out:
return changeset;
}
static void
libhal_changeset_append (LibHalChangeSet *changeset, LibHalChangeSetElement *elem)
{
if (changeset->head == NULL) {
changeset->head = elem;
changeset->tail = elem;
elem->next = NULL;
elem->prev = NULL;
} else {
elem->prev = changeset->tail;
elem->next = NULL;
elem->prev->next = elem;
changeset->tail = elem;
}
}
/**
* libhal_device_set_property_string:
* @changeset: the changeset
* @key: key of property
* @value: the value to set
*
* Set a property.
*
* Returns: FALSE on OOM
*/
dbus_bool_t
libhal_changeset_set_property_string (LibHalChangeSet *changeset, const char *key, const char *value)
{
LibHalChangeSetElement *elem;
elem = calloc (1, sizeof (LibHalChangeSetElement));
if (elem == NULL)
goto out;
elem->key = strdup (key);
if (elem->key == NULL) {
free (elem);
elem = NULL;
goto out;
}
elem->change_type = LIBHAL_PROPERTY_TYPE_STRING;
elem->value.val_str = strdup (value);
if (elem->value.val_str == NULL) {
free (elem->key);
free (elem);
elem = NULL;
goto out;
}
libhal_changeset_append (changeset, elem);
out:
return elem != NULL;
}
/**
* libhal_device_set_property_int:
* @changeset: the changeset
* @key: key of property
* @value: the value to set
*
* Set a property.
*
* Returns: FALSE on OOM
*/
dbus_bool_t
libhal_changeset_set_property_int (LibHalChangeSet *changeset, const char *key, dbus_int32_t value)
{
LibHalChangeSetElement *elem;
elem = calloc (1, sizeof (LibHalChangeSetElement));
if (elem == NULL)
goto out;
elem->key = strdup (key);
if (elem->key == NULL) {
free (elem);
elem = NULL;
goto out;
}
elem->change_type = LIBHAL_PROPERTY_TYPE_INT32;
elem->value.val_int = value;
libhal_changeset_append (changeset, elem);
out:
return elem != NULL;
}
/**
* libhal_device_set_property_uint64:
* @changeset: the changeset
* @key: key of property
* @value: the value to set
*
* Set a property.
*
* Returns: FALSE on OOM
*/
dbus_bool_t
libhal_changeset_set_property_uint64 (LibHalChangeSet *changeset, const char *key, dbus_uint64_t value)
{
LibHalChangeSetElement *elem;
elem = calloc (1, sizeof (LibHalChangeSetElement));
if (elem == NULL)
goto out;
elem->key = strdup (key);
if (elem->key == NULL) {
free (elem);
elem = NULL;
goto out;
}
elem->change_type = LIBHAL_PROPERTY_TYPE_UINT64;
elem->value.val_uint64 = value;
libhal_changeset_append (changeset, elem);
out:
return elem != NULL;
}
/**
* libhal_device_set_property_double:
* @changeset: the changeset
* @key: key of property
* @value: the value to set
*
* Set a property.
*
* Returns: FALSE on OOM
*/
dbus_bool_t
libhal_changeset_set_property_double (LibHalChangeSet *changeset, const char *key, double value)
{
LibHalChangeSetElement *elem;
elem = calloc (1, sizeof (LibHalChangeSetElement));
if (elem == NULL)
goto out;
elem->key = strdup (key);
if (elem->key == NULL) {
free (elem);
elem = NULL;
goto out;
}
elem->change_type = LIBHAL_PROPERTY_TYPE_DOUBLE;
elem->value.val_double = value;
libhal_changeset_append (changeset, elem);
out:
return elem != NULL;
}
/**
* libhal_device_set_property_bool:
* @changeset: the changeset
* @key: key of property
* @value: the value to set
*
* Set a property.
*
* Returns: FALSE on OOM
*/
dbus_bool_t
libhal_changeset_set_property_bool (LibHalChangeSet *changeset, const char *key, dbus_bool_t value)
{
LibHalChangeSetElement *elem;
elem = calloc (1, sizeof (LibHalChangeSetElement));
if (elem == NULL)
goto out;
elem->key = strdup (key);
if (elem->key == NULL) {
free (elem);
elem = NULL;
goto out;
}
elem->change_type = LIBHAL_PROPERTY_TYPE_BOOLEAN;
elem->value.val_bool = value;
libhal_changeset_append (changeset, elem);
out:
return elem != NULL;
}
/**
* libhal_device_set_property_strlist:
* @changeset: the changeset
* @key: key of property
* @value: the value to set - NULL terminated array of strings
*
* Set a property.
*
* Returns: FALSE on OOM
*/
dbus_bool_t
libhal_changeset_set_property_strlist (LibHalChangeSet *changeset, const char *key, const char **value)
{
LibHalChangeSetElement *elem;
char **value_copy;
int len;
int i, j;
elem = calloc (1, sizeof (LibHalChangeSetElement));
if (elem == NULL)
goto out;
elem->key = strdup (key);
if (elem->key == NULL) {
free (elem);
elem = NULL;
goto out;
}
for (i = 0; value[i] != NULL; i++)
;
len = i;
value_copy = calloc (len + 1, sizeof (char *));
if (value_copy == NULL) {
free (elem->key);
free (elem);
elem = NULL;
goto out;
}
for (i = 0; i < len; i++) {
value_copy[i] = strdup (value[i]);
if (value_copy[i] == NULL) {
for (j = 0; j < i; j++) {
free (value_copy[j]);
}
free (value_copy);
free (elem->key);
free (elem);
elem = NULL;
goto out;
}
}
value_copy[i] = NULL;
elem->change_type = LIBHAL_PROPERTY_TYPE_STRLIST;
elem->value.val_strlist = value_copy;
libhal_changeset_append (changeset, elem);
out:
return elem != NULL;
}
/**
* libhal_device_commit_changeset:
* @ctx: the context for the connection to hald
* @changeset: the changeset to commit
* @error: pointer to an initialized dbus error object for returning errors or NULL
*
* Commit a changeset to the daemon.
*
* Returns: True if the changeset was committed on the daemon side
*/
dbus_bool_t
libhal_device_commit_changeset (LibHalContext *ctx, LibHalChangeSet *changeset, DBusError *error)
{
LibHalChangeSetElement *elem;
DBusMessage *message;
DBusMessage *reply;
DBusError _error;
DBusMessageIter iter;
DBusMessageIter sub;
DBusMessageIter sub2;
DBusMessageIter sub3;
DBusMessageIter sub4;
int i;
LIBHAL_CHECK_LIBHALCONTEXT(ctx, FALSE);
if (changeset->head == NULL) {
return TRUE;
}
message = dbus_message_new_method_call ("org.freedesktop.Hal", changeset->udi,
"org.freedesktop.Hal.Device",
"SetMultipleProperties");
if (message == NULL) {
fprintf (stderr, "%s %d : Couldn't allocate D-BUS message\n", __FILE__, __LINE__);
return FALSE;
}
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_open_container (&iter,
DBUS_TYPE_ARRAY,
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
&sub);
for (elem = changeset->head; elem != NULL; elem = elem->next) {
dbus_message_iter_open_container (&sub,
DBUS_TYPE_DICT_ENTRY,
NULL,
&sub2);
dbus_message_iter_append_basic (&sub2, DBUS_TYPE_STRING, &(elem->key));
switch (elem->change_type) {
case LIBHAL_PROPERTY_TYPE_STRING:
dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &sub3);
dbus_message_iter_append_basic (&sub3, DBUS_TYPE_STRING, &(elem->value.val_str));
dbus_message_iter_close_container (&sub2, &sub3);
break;
case LIBHAL_PROPERTY_TYPE_STRLIST:
dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT,
DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING, &sub3);
dbus_message_iter_open_container (&sub3, DBUS_TYPE_ARRAY,
DBUS_TYPE_STRING_AS_STRING, &sub4);
for (i = 0; elem->value.val_strlist[i] != NULL; i++) {
dbus_message_iter_append_basic (&sub4, DBUS_TYPE_STRING,
&(elem->value.val_strlist[i]));
}
dbus_message_iter_close_container (&sub3, &sub4);
dbus_message_iter_close_container (&sub2, &sub3);
break;
case LIBHAL_PROPERTY_TYPE_INT32:
dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_INT32_AS_STRING, &sub3);
dbus_message_iter_append_basic (&sub3, DBUS_TYPE_INT32, &(elem->value.val_int));
dbus_message_iter_close_container (&sub2, &sub3);
break;
case LIBHAL_PROPERTY_TYPE_UINT64:
dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_UINT64_AS_STRING, &sub3);
dbus_message_iter_append_basic (&sub3, DBUS_TYPE_UINT64, &(elem->value.val_uint64));
dbus_message_iter_close_container (&sub2, &sub3);
break;
case LIBHAL_PROPERTY_TYPE_DOUBLE:
dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_DOUBLE_AS_STRING, &sub3);
dbus_message_iter_append_basic (&sub3, DBUS_TYPE_DOUBLE, &(elem->value.val_double));
dbus_message_iter_close_container (&sub2, &sub3);
break;
case LIBHAL_PROPERTY_TYPE_BOOLEAN:
dbus_message_iter_open_container (&sub2, DBUS_TYPE_VARIANT, DBUS_TYPE_BOOLEAN_AS_STRING,&sub3);
dbus_message_iter_append_basic (&sub3, DBUS_TYPE_BOOLEAN, &(elem->value.val_bool));
dbus_message_iter_close_container (&sub2, &sub3);
break;
default:
fprintf (stderr, "%s %d : unknown change_type %d\n", __FILE__, __LINE__, elem->change_type);
break;
}
dbus_message_iter_close_container (&sub, &sub2);
}
dbus_message_iter_close_container (&iter, &sub);
dbus_error_init (&_error);
reply = dbus_connection_send_with_reply_and_block (ctx->connection,
message, -1,
&_error);
dbus_move_error (&_error, error);
if (error != NULL && dbus_error_is_set (error)) {
fprintf (stderr,
"%s %d : %s\n",
__FILE__, __LINE__, error->message);
dbus_message_unref (message);
return FALSE;
}
if (reply == NULL) {
dbus_message_unref (message);
return FALSE;
}
return TRUE;
}
/**
* libhal_device_free_changeset:
* @changeset: the changeset to free
*
* Free a changeset.
*/
void
libhal_device_free_changeset (LibHalChangeSet *changeset)
{
LibHalChangeSetElement *elem;
LibHalChangeSetElement *elem2;
for (elem = changeset->head; elem != NULL; elem = elem2) {
elem2 = elem->next;
switch (elem->change_type) {
case LIBHAL_PROPERTY_TYPE_STRING:
free (elem->value.val_str);
break;
case LIBHAL_PROPERTY_TYPE_STRLIST:
libhal_free_string_array (elem->value.val_strlist);
break;
/* explicit fallthrough */
case LIBHAL_PROPERTY_TYPE_INT32:
case LIBHAL_PROPERTY_TYPE_UINT64:
case LIBHAL_PROPERTY_TYPE_DOUBLE:
case LIBHAL_PROPERTY_TYPE_BOOLEAN:
break;
default:
fprintf (stderr, "%s %d : unknown change_type %d\n", __FILE__, __LINE__, elem->change_type);
break;
}
free (elem);
}
free (changeset->udi);
free (changeset);
}