EFL 1.7 svn doobies
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 30 Aug 2012 09:54:57 +0000 (09:54 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 30 Aug 2012 09:54:57 +0000 (09:54 +0000)
git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/branches/e_dbus-1.7@75862 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

118 files changed:
.gitignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
doc/Doxyfile.in [new file with mode: 0644]
doc/Makefile.am [new file with mode: 0644]
doc/e.css [new file with mode: 0644]
doc/foot.html [new file with mode: 0644]
doc/head.html [new file with mode: 0644]
doc/images/e.png [new file with mode: 0644]
doc/images/edoxy.css [new file with mode: 0644]
doc/images/foot_bg.png [new file with mode: 0644]
doc/images/head_bg.png [new file with mode: 0644]
doc/images/menu_bg.png [new file with mode: 0644]
doc/images/menu_bg_current.png [new file with mode: 0644]
doc/images/menu_bg_hover.png [new file with mode: 0644]
doc/images/menu_bg_last.png [new file with mode: 0644]
doc/images/menu_bg_unsel.png [new file with mode: 0644]
e_dbus.spec.in [new file with mode: 0644]
ebluez.pc.in [new file with mode: 0644]
econnman-0.7x.pc.in [new file with mode: 0644]
edbus.pc.in [new file with mode: 0644]
ehal.pc.in [new file with mode: 0644]
enotify.pc.in [new file with mode: 0644]
eofono.pc.in [new file with mode: 0644]
eukit.pc.in [new file with mode: 0644]
m4/ac_attribute.m4 [new file with mode: 0644]
m4/efl_binary.m4 [new file with mode: 0644]
m4/efl_compiler_flag.m4 [new file with mode: 0644]
m4/efl_doxygen.m4 [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/bin/Makefile.am [new file with mode: 0644]
src/bin/async_client_test.c [new file with mode: 0644]
src/bin/async_server_test.c [new file with mode: 0644]
src/bin/e_dbus_bluez_test.c [new file with mode: 0644]
src/bin/e_dbus_connman0_7x_test.c [new file with mode: 0644]
src/bin/e_dbus_connman0_7x_test_api.c [new file with mode: 0644]
src/bin/e_dbus_ofono_test.c [new file with mode: 0644]
src/bin/e_dbus_ukit_test.c [new file with mode: 0644]
src/bin/logo.png [new file with mode: 0644]
src/bin/notification_daemon.c [new file with mode: 0644]
src/bin/notify-send.c [new file with mode: 0644]
src/bin/notify.c [new file with mode: 0644]
src/bin/performance.c [new file with mode: 0644]
src/bin/test.c [new file with mode: 0644]
src/bin/test_client.c [new file with mode: 0644]
src/lib/Makefile.am [new file with mode: 0644]
src/lib/bluez/E_Bluez.h [new file with mode: 0644]
src/lib/bluez/Makefile.am [new file with mode: 0644]
src/lib/bluez/e_bluez.c [new file with mode: 0644]
src/lib/bluez/e_bluez_adapter.c [new file with mode: 0644]
src/lib/bluez/e_bluez_device.c [new file with mode: 0644]
src/lib/bluez/e_bluez_devicefound.c [new file with mode: 0644]
src/lib/bluez/e_bluez_element.c [new file with mode: 0644]
src/lib/bluez/e_bluez_manager.c [new file with mode: 0644]
src/lib/bluez/e_bluez_private.h [new file with mode: 0644]
src/lib/connman0_7x/E_Connman.h [new file with mode: 0644]
src/lib/connman0_7x/Makefile.am [new file with mode: 0644]
src/lib/connman0_7x/e_connman.c [new file with mode: 0644]
src/lib/connman0_7x/e_connman_element.c [new file with mode: 0644]
src/lib/connman0_7x/e_connman_manager.c [new file with mode: 0644]
src/lib/connman0_7x/e_connman_private.h [new file with mode: 0644]
src/lib/connman0_7x/e_connman_profile.c [new file with mode: 0644]
src/lib/connman0_7x/e_connman_service.c [new file with mode: 0644]
src/lib/connman0_7x/e_connman_technology.c [new file with mode: 0644]
src/lib/dbus/E_DBus.h [new file with mode: 0644]
src/lib/dbus/Makefile.am [new file with mode: 0644]
src/lib/dbus/e_dbus.c [new file with mode: 0644]
src/lib/dbus/e_dbus_interfaces.c [new file with mode: 0644]
src/lib/dbus/e_dbus_message.c [new file with mode: 0644]
src/lib/dbus/e_dbus_methods.c [new file with mode: 0644]
src/lib/dbus/e_dbus_object.c [new file with mode: 0644]
src/lib/dbus/e_dbus_private.h [new file with mode: 0644]
src/lib/dbus/e_dbus_signal.c [new file with mode: 0644]
src/lib/dbus/e_dbus_util.c [new file with mode: 0644]
src/lib/hal/E_Hal.h [new file with mode: 0644]
src/lib/hal/HAL 0.5.10 Specification.html [new file with mode: 0644]
src/lib/hal/Makefile.am [new file with mode: 0644]
src/lib/hal/e_hal_device.c [new file with mode: 0644]
src/lib/hal/e_hal_device.h [new file with mode: 0644]
src/lib/hal/e_hal_main.c [new file with mode: 0644]
src/lib/hal/e_hal_manager.c [new file with mode: 0644]
src/lib/hal/e_hal_manager.h [new file with mode: 0644]
src/lib/hal/e_hal_private.h [new file with mode: 0644]
src/lib/hal/e_hal_util.c [new file with mode: 0644]
src/lib/hal/e_hal_util.h [new file with mode: 0644]
src/lib/notification/E_Notification_Daemon.h [new file with mode: 0644]
src/lib/notification/E_Notify.h [new file with mode: 0644]
src/lib/notification/Makefile.am [new file with mode: 0644]
src/lib/notification/client.c [new file with mode: 0644]
src/lib/notification/daemon.c [new file with mode: 0644]
src/lib/notification/e_notify_private.h [new file with mode: 0644]
src/lib/notification/marshal.c [new file with mode: 0644]
src/lib/notification/notification-spec.xml [new file with mode: 0644]
src/lib/notification/notification.c [new file with mode: 0644]
src/lib/ofono/E_Ofono.h [new file with mode: 0644]
src/lib/ofono/Makefile.am [new file with mode: 0644]
src/lib/ofono/e_ofono.c [new file with mode: 0644]
src/lib/ofono/e_ofono_element.c [new file with mode: 0644]
src/lib/ofono/e_ofono_manager.c [new file with mode: 0644]
src/lib/ofono/e_ofono_modem.c [new file with mode: 0644]
src/lib/ofono/e_ofono_network_reg.c [new file with mode: 0644]
src/lib/ofono/e_ofono_private.h [new file with mode: 0644]
src/lib/ofono/e_ofono_sms.c [new file with mode: 0644]
src/lib/ukit/E_Ukit.h [new file with mode: 0644]
src/lib/ukit/Makefile.am [new file with mode: 0644]
src/lib/ukit/e_udisks.c [new file with mode: 0644]
src/lib/ukit/e_ukit_main.c [new file with mode: 0644]
src/lib/ukit/e_ukit_private.h [new file with mode: 0644]
src/lib/ukit/e_ukit_private_util.c [new file with mode: 0644]
src/lib/ukit/e_ukit_util.c [new file with mode: 0644]
src/lib/ukit/e_upower.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..4d3e8fd
--- /dev/null
@@ -0,0 +1,57 @@
+*.o
+*.a
+*.lo
+*.la
+Makefile
+Makefile.in
+.libs
+.deps
+/ABOUT-NLS
+/aclocal.m4
+/autom4te.cache/
+/compile
+/config.cache
+/config.cache-env
+/config.guess
+/config.h
+/config.h.in
+/config.log
+/config.status
+/config.sub
+/configure
+/depcomp
+/e_dbus.spec
+/ebluez.pc
+/econnman.pc
+/econnman-0.7x.pc
+/edbus.pc
+/ehal.pc
+/enotify.pc
+/eofono.pc
+/eukit.pc
+/install-sh
+/libtool
+/ltmain.sh
+/m4/libtool.m4
+/m4/ltoptions.m4
+/m4/ltsugar.m4
+/m4/ltversion.m4
+/m4/lt~obsolete.m4
+/missing
+/src/bin/e-notify-send
+/src/bin/e_dbus_bluez_test
+/src/bin/e_dbus_connman_test
+/src/bin/e_dbus_connman_test_api
+/src/bin/e_dbus_connman0_7x_test
+/src/bin/e_dbus_connman0_7x_test_api
+/src/bin/e_dbus_notification_daemon
+/src/bin/e_dbus_notify
+/src/bin/e_dbus_ofono_test
+/src/bin/e_dbus_test
+/src/bin/e_dbus_test_client
+/src/bin/e_dbus_performance
+/src/bin/e_dbus_async_client_test
+/src/bin/e_dbus_async_server_test
+/src/bin/e_dbus_ukit_test
+/stamp-h1
+/doc/Doxyfile
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..1e246e1
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,9 @@
+Brian Mattern <rephorm@rephorm.com>
+Mathieu Taillefumier <mathieu.taillefumier@free.fr>
+Mike Blumenkrantz (zmike/discomfitor) michael.blumenkrantz@gmail.com
+Bruno Dilly <bdilly@profusion.mobi>
+Gustavo F. Padovan <padovan@profusion.mobi>
+João Paulo Rechi Vita <jprvita@profusion.mobi>
+Sebastian Dransfeld <sd@tango.flipp.net>
+Lucas De Marchi <lucas.demarchi@profusion.mobi>
+Halton Huo <halton.huo@intel.com>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..fcba206
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,25 @@
+Copyright notice for E_Dbus:
+
+Copyright (C) 2006-2011 Brian Mattern and various contributors (see AUTHORS)
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright 
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..4976c8b
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,77 @@
+2011-01-29  Carsten Haitzler (The Rasterman)
+
+        1.0.0 release
+
+2011-02-25  Cedric BAIL
+
+       * Fix build with DSO.
+
+2011-03-19  Mike Blumenkrantz
+
+        * Fix crash in e-notify-send when invalid DBUS_SESSION_BUS_ADDRESS is specified
+
+2011-04-27  Carsten Haitzler (The Rasterman)
+
+        * Fix bug when app has no idle time (always busy), idlers
+        can't run to process edbus dispatches. Move this to an idle
+        enterer that wil be run.
+
+2011-07-26  Libor Zoubek <lzoubek@jezzovo.net>
+
+        * Add support for notification protocol 1.2 into e_dbus by
+        adding spec version string support.
+
+2011-10-27  Mike Blumenkrantz
+
+        * Added e_notification_action_id_get and e_notification_action_name_get
+
+2011-11-03  Mike Blumenkrantz
+
+        * Added more methods for manipulating notification hints
+
+2011-11-06  Mike Blumenkrantz
+
+        * Add e_notification_image_init for filling in values from an Evas_Object
+
+2011-11-11  Carsten Haitzler (The Rasterman)
+
+        * Fix DSO linking to edbus to include libdbus linking and includes
+
+2011-11-27  Mike Blumenkrantz
+
+        * Fix case where fd handler could be added twice for dbus fd
+
+2011-12-02  Carsten Haitzler (The Rasterman)
+
+        * 1.1.0 release
+
+2011-12-02  Mike Blumenkrantz
+
+        * Fixed use of dbus_message_iter_open_container in enotify to prevent crashing when sending an image
+
+2011-12-10  Mike Blumenkrantz
+
+        * Fixed use of eina_log in enotify-daemon
+
+2012-01-17 Dave Andreoli
+
+        * Fixed use of the 'object path' type in ukit
+
+2012-04-26 Carsten Haitzler (The Rasterman)
+
+        1.2.0 release
+
+2012-07-05 José Roberto de Souza
+
+        * Use idler instead of idle_enterer for processing messages
+        * Listen and update the 'sender unique name' of signals
+
+2012-07-13 José Roberto de Souza
+
+        * Fix properties handling
+        * Check if interface already exists before attaching
+        * Fix missing DBus.Properties attach
+
+2012-08-20 Mike Blumenkrantz
+
+        * Add null checks for dbus functions
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..23e5f25
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,236 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
+Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about.  Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory.  After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).  Here is a another example:
+
+     /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
+configuration-related scripts to be executed by `/bin/bash'.
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..1d9b0ec
--- /dev/null
@@ -0,0 +1,80 @@
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = src doc
+
+MAINTAINERCLEANFILES = \
+Makefile.in \
+aclocal.m4 \
+config.guess \
+config.h.in \
+config.h.in~ \
+config.sub \
+configure \
+depcomp \
+install-sh \
+ltmain.sh \
+missing \
+$(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.gz \
+$(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.bz2 \
+$(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-doc.tar.bz2 \
+m4/libtool.m4 \
+m4/lt~obsolete.m4 \
+m4/ltoptions.m4 \
+m4/ltsugar.m4 \
+m4/ltversion.m4
+
+pkgconfigdir = $(libdir)/pkgconfig
+
+if BUILD_EHAL
+EHAL_PC = ehal.pc
+endif
+
+if BUILD_ENOTIFY
+ENOTIFY_PC = enotify.pc
+endif
+
+if BUILD_ECONNMAN0_7X
+ECONNMAN_PC = econnman-0.7x.pc
+endif
+
+if BUILD_EBLUEZ
+EBLUEZ_PC = ebluez.pc
+endif
+
+if BUILD_EOFONO
+EOFONO_PC = eofono.pc
+endif
+
+if BUILD_EUKIT
+EUKIT_PC = eukit.pc
+endif
+
+pkgconfig_DATA = edbus.pc $(EBLUEZ_PC) $(ECONNMAN_PC) $(EHAL_PC) $(ENOTIFY_PC) $(EOFONO_PC) $(EUKIT_PC)
+
+EXTRA_DIST = \
+AUTHORS \
+COPYING \
+README \
+$(pkgconfig_DATA) \
+autogen.sh \
+ebluez.pc.in \
+econnman-0.7x.pc.in \
+edbus.pc.in \
+ehal.pc.in \
+enotify.pc.in \
+eofono.pc.in \
+eukit.pc.in \
+e_dbus.spec \
+e_dbus.spec.in \
+m4/ac_attribute.m4 \
+m4/efl_binary.m4 \
+m4/efl_compiler_flag.m4 \
+m4/efl_doxygen.m4
+
+.PHONY: doc
+
+# Documentation
+
+doc:
+       @echo "entering doc/"
+       make -C doc doc
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..5dff7db
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,51 @@
+E_dbus 1.7.0
+
+Changes since E_dbus 1.2.0:
+---------------------------
+
+Improvements:
+
+   * More null checks for API's
+
+Fixes:
+
+   * Properties handling
+   * Interface attach to not attach if already there
+   * Missing DBus.Properties attach
+
+Changes since E_dbus 1.1.0:
+---------------------------
+
+Fixes:
+
+   * enotify:
+    - use of dbus_message_iter_open_container prevent crash on image send.
+
+Improvements:
+
+   * eukit:
+    - Correctly handle the dbus type 'object path', it is a string after all.
+   * enotify:
+    - use eina_log better in enotify-daemon.
+
+Changes since E_dbus 1.0.0:
+---------------------------
+
+Additions:
+
+    * e_notification_action_id_get
+    * e_notification_action_name_get
+    * e_notification_image_init
+    * e_connman: sync api with connman-0.7x
+
+Fixes:
+
+    * DSO linking issues fixed
+    * crash on e-notify-send with invalid session bus set
+    * when app has no idle time, e_dbus's idlers dont process anything
+    * error when trying to add duplicate fd handler for dbus fd
+
+Improvements:
+
+    * notification protocol 1.2 support
+    * e_connman supports connman-0.7x api, warns that it is unstable.
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e6f8005
--- /dev/null
+++ b/README
@@ -0,0 +1,84 @@
+E_dbus 1.7.0
+
+******************************************************************************
+
+ FOR ANY ISSUES PLEASE EMAIL:
+ enlightenment-devel@lists.sourceforge.net
+  
+******************************************************************************
+  
+Requirements:
+-------------
+
+Must:
+  libc
+  libdbus
+  eina (at least 1.1.0)
+  ecore (at least 1.1.0)
+
+Recommended:
+  evas (at least 1.1.0)
+
+This is the start of some basic convenience wrappers around dbus to ease
+integrating dbus with EFL based applications.
+
+When using e_dbus, direct use of the low level dbus api is still heavily
+required for processing messages.
+
+A few things to note:
+
+e_dbus_bus_get() currently creates a new private connection to whichever bus
+is passed in, and hooks this into the ecore main loop. At some point, we
+should implement internal refcounting and sharing of these private
+connections (one for each bus type) so that e.g. multiple modules in an app
+can reuse the same connection. libdbus implements its own shared connections
+(available via dbus_bus_get()), but the final reference is always retained by
+libdbus iteself, causing any cleanup handlers on the connection to only be
+called at app exit. Thus, if a module hooks a connection in to the mainloop,
+there is no way to clean up fully before unloading the module, causing issues.
+
+Patches can be sent to the enlightenment dev mailing list, or, if you have
+commit access, feel free to commit.
+
+
+ABOUT PROVIDED MODULES:
+-----------------------
+
+E_DBus provides easy C API for some D-Bus services, the
+org.freedesktop.DBus interface is implemented into libedbus/E_DBus.h
+itself, while the following modules provides more and their respective
+version:
+
+ * bluez(v4.9x): barebones to toggle state and change visibility.
+ * connman0.7x: complete manager, service and technology.
+ * hal(v0.5.x): deprecated, provides basic for e17. See ukit.
+ * notification(v0.7.x): complete client and server.
+ * ofono(v0.5x, v1.0): barebones to toggle state.
+ * ukit(upower-v0.9.x, udisks-1.0.x): most of upower, status api from udisks.
+
+
+API STABILITY:
+--------------
+
+Everything but libedbus (E_DBus.h) is subject to API or ABI stability
+of the provided service or protocol specification. If the service
+change their API, we'll break our API.
+
+The library/module versioning will be used at the name, leaving the
+soversion synchronized with libedbus.so.
+
+Examples:
+ * libeconnman0_7x.so.1.1.0 is the service connman at version
+   0.7x created with libedbus.so.1.1.0.
+ * econnman-0.7x.pc (Version: 1.1.0) is the service connman at version
+   0.7x created with edbus.pc (Version: 1.1.0).
+
+
+------------------------------------------------------------------------------
+COMPILING AND INSTALLING:
+
+  ./configure
+  make
+(do this as root unless you are installing in your users directories):
+  make install
+  
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..00116ea
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f aclocal.m4 ltmain.sh
+
+touch README
+touch ABOUT-NLS
+
+echo "Running aclocal..." ; aclocal $ACLOCAL_FLAGS -I m4 || exit 1
+echo "Running autoheader..." ; autoheader || exit 1
+echo "Running autoconf..." ; autoconf || exit 1
+echo "Running libtoolize..." ; (libtoolize --copy --automake || glibtoolize --automake) || exit 1
+echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1
+
+W=0
+
+rm -f config.cache-env.tmp
+echo "OLD_PARM=\"$@\"" >> config.cache-env.tmp
+echo "OLD_CFLAGS=\"$CFLAGS\"" >> config.cache-env.tmp
+echo "OLD_PATH=\"$PATH\"" >> config.cache-env.tmp
+echo "OLD_PKG_CONFIG_PATH=\"$PKG_CONFIG_PATH\"" >> config.cache-env.tmp
+echo "OLD_LDFLAGS=\"$LDFLAGS\"" >> config.cache-env.tmp
+
+cmp config.cache-env.tmp config.cache-env >> /dev/null
+if [ $? -ne 0 ]; then
+       W=1;
+fi
+
+if [ $W -ne 0 ]; then
+       echo "Cleaning configure cache...";
+       rm -f config.cache config.cache-env
+       mv config.cache-env.tmp config.cache-env
+else
+       rm -f config.cache-env.tmp
+fi
+
+if [ -z "$NOCONFIGURE" ]; then
+       ./configure -C "$@"
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..0c665b0
--- /dev/null
@@ -0,0 +1,411 @@
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+m4_define([v_maj], [1])
+m4_define([v_min], [7])
+m4_define([v_mic], [0])
+m4_define([v_rev], m4_esyscmd([(svnversion "${SVN_REPO_PATH:-.}" | grep -v '\(export\|Unversioned directory\)' || echo 0) | awk -F : '{printf("%s\n", $1);}' | tr -d ' :MSP\n']))
+m4_if(v_rev, [0], [m4_define([v_rev], m4_esyscmd([git log 2> /dev/null | (grep -m1 git-svn-id || echo 0) | sed -e 's/.*@\([0-9]*\).*/\1/' | tr -d '\n']))])
+##--   When released, remove the dnl on the below line
+m4_undefine([v_rev])
+##--   When doing snapshots - change soname. remove dnl on below line
+dnl m4_define([relname], [ver-pre-svn-07])
+dnl m4_define([v_rel], [-release relname])
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+m4_ifdef([v_rev], [m4_define([v_ver], [v_maj.v_min.v_mic.v_rev])],
+[m4_define([v_ver], [v_maj.v_min.v_mic])])
+m4_define([lt_cur], m4_eval(v_maj + v_min))
+m4_define([lt_rev], v_mic)
+m4_define([lt_age], v_min)
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+
+AC_INIT([e_dbus], [v_ver], [enlightenment-devel@lists.sourceforge.net])
+AC_PREREQ([2.52])
+AC_CONFIG_SRCDIR([configure.ac])
+AC_CONFIG_MACRO_DIR([m4])
+
+AC_CONFIG_HEADERS([config.h])
+AH_TOP([
+#ifndef EFL_CONFIG_H__
+#define EFL_CONFIG_H__
+])
+AH_BOTTOM([
+#endif /* EFL_CONFIG_H__ */
+])
+
+AM_INIT_AUTOMAKE([1.6 dist-bzip2])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AC_LIBTOOL_WIN32_DLL
+define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl
+define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
+AC_PROG_LIBTOOL
+
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+m4_ifdef([v_rev], , [m4_define([v_rev], [0])])
+m4_ifdef([v_rel], , [m4_define([v_rel], [])])
+AC_DEFINE_UNQUOTED(VMAJ, [v_maj], [Major version])
+AC_DEFINE_UNQUOTED(VMIN, [v_min], [Minor version])
+AC_DEFINE_UNQUOTED(VMIC, [v_mic], [Micro version])
+AC_DEFINE_UNQUOTED(VREV, [v_rev], [Revison])
+version_info="lt_cur:lt_rev:lt_age"
+release_info="v_rel"
+AC_SUBST(version_info)
+AC_SUBST(release_info)
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+VMAJ=v_maj
+AC_SUBST(VMAJ)
+
+### Needed information
+
+AC_CANONICAL_BUILD
+AC_CANONICAL_HOST
+
+want_ebluez="yes"
+want_econnman0_7x="yes"
+want_ehal="yes"
+want_enotify="yes"
+want_eofono="yes"
+want_eukit="yes"
+
+case "$host_os" in
+   mingw*)
+      want_ebluez="no"
+      want_econnman0_7x="no"
+      want_ehal="no"
+      want_enotify="no"
+      want_eofono="no"
+      want_eukit="no"
+      ;;
+esac
+
+requirement_ebluez="edbus >= 1.6.99"
+requirement_econnman0_7x="edbus >= 1.6.99"
+requirement_edbus="ecore >= 1.6.99 eina >= 1.6.99 dbus-1 >= 0.62"
+requirement_ehal="edbus >= 1.6.99"
+requirement_enotify="edbus >= 1.6.99"
+requirement_eofono="edbus >= 1.6.99"
+requirement_eukit="edbus >= 1.6.99"
+requirement_dbus="dbus-1 >= 0.62"
+
+### Additional options to configure
+
+dnl Check enabled modules to build
+
+AC_ARG_ENABLE([ebluez],
+   [AC_HELP_STRING([--enable-ebluez], [Enable ebluez build])],
+   [enable_ebluez=$enableval],
+   [enable_ebluez="${want_ebluez}"])
+
+AC_ARG_ENABLE([econnman0_7x],
+   [AC_HELP_STRING([--enable-econnman0_7x], [Enable econnman 0.7x build])],
+   [enable_econnman0_7x=$enableval],
+   [enable_econnman0_7x="${want_econnman0_7x}"])
+
+AC_ARG_ENABLE([ehal],
+   [AC_HELP_STRING([--disable-ehal], [Disable ehal build])],
+   [enable_ehal=$enableval],
+   [enable_ehal="${want_ehal}"])
+
+AC_ARG_ENABLE([enotify],
+   [AC_HELP_STRING([--disable-enotify], [Disable enotify build])],
+   [enable_enotify=$enableval],
+   [enable_enotify="${want_enotify}"])
+
+AC_ARG_ENABLE([eofono],
+   [AC_HELP_STRING([--enable-eofono], [Enable eofono build])],
+   [enable_eofono=$enableval],
+   [enable_eofono="${want_eofono}"])
+
+AC_ARG_ENABLE([eukit],
+   [AC_HELP_STRING([--disable-eukit], [Disable eukit build])],
+   [enable_eukit=$enableval],
+   [enable_eukit="${want_eukit}"])
+
+### Checks for programs
+
+AC_PROG_CC
+AM_PROG_CC_C_O
+
+# pkg-config
+PKG_PROG_PKG_CONFIG
+
+# Check whether pkg-config supports Requires.private
+if $PKG_CONFIG --atleast-pkgconfig-version 0.22 ; then
+   pkgconfig_requires_private="Requires.private"
+else
+   pkgconfig_requires_private="Requires"
+fi
+AC_SUBST(pkgconfig_requires_private)
+
+# doxygen program for documentation building
+EFL_CHECK_DOXYGEN([build_doc="yes"], [build_doc="no"])
+
+
+### Checks for libraries
+
+PKG_CHECK_MODULES([DBUS], [dbus-1 >= 0.62])
+dbus_libs="$DBUS_LIBS"
+dbus_cflags="$DBUS_CFLAGS"
+AC_SUBST(dbus_libs)
+AC_SUBST(dbus_cflags)
+PKG_CHECK_MODULES([EDBUS], [ecore >= 1.6.99 eina >= 1.6.99 dbus-1 >= 0.62])
+
+# Find out the version of DBUS we're using
+dbus_version=`pkg-config --modversion dbus-1`
+DBUS_VERSION_MAJOR=`echo $dbus_version | awk -F. '{print $1}'`
+DBUS_VERSION_MINOR=`echo $dbus_version | awk -F. '{print $2}'`
+DBUS_VERSION_MICRO=`echo $dbus_version | awk -F. '{print $3}'`
+
+if test "z$DBUS_VERSION_MAJOR" = "z" ; then
+   DBUS_VERSION_MAJOR="0"
+fi
+
+if test "z$DBUS_VERSION_MINOR" = "z" ; then
+   DBUS_VERSION_MINOR="0"
+fi
+
+if test "z$DBUS_VERSION_MICRO" = "z" ; then
+   DBUS_VERSION_MICRO="0"
+fi
+
+DBUS_VERSION_CFLAGS="$DBUS_VERSION_CFLAGS -DDBUS_VERSION_MAJOR=$DBUS_VERSION_MAJOR"
+DBUS_VERSION_CFLAGS="$DBUS_VERSION_CFLAGS -DDBUS_VERSION_MINOR=$DBUS_VERSION_MINOR"
+DBUS_VERSION_CFLAGS="$DBUS_VERSION_CFLAGS -DDBUS_VERSION_MICRO=$DBUS_VERSION_MICRO"
+AC_SUBST(DBUS_VERSION_CFLAGS)
+
+# Dependencies for the libraries
+if test "x${enable_enotify}" = "xyes" ; then
+   PKG_CHECK_MODULES([EVAS],
+      [evas >= 1.6.99],
+      [requirement_enotify="evas >= 1.6.99 ${requirement_enotify}"],
+      [enable_enotify="no"])
+fi
+
+AM_CONDITIONAL([BUILD_EBLUEZ],   [test "x${enable_ebluez}"   = "xyes"])
+AM_CONDITIONAL([BUILD_ECONNMAN0_7X], [test "x${enable_econnman0_7x}" = "xyes"])
+AM_CONDITIONAL([BUILD_EHAL],     [test "x${enable_ehal}"     = "xyes"])
+AM_CONDITIONAL([BUILD_ENOTIFY],  [test "x${enable_enotify}"  = "xyes"])
+AM_CONDITIONAL([BUILD_EOFONO],   [test "x${enable_eofono}"   = "xyes"])
+AM_CONDITIONAL([BUILD_EUKIT],    [test "x${enable_eukit}"    = "xyes"])
+
+# Dependencies for the binaries
+
+EFL_ENABLE_BIN([edbus-test], ["yes"])
+EFL_ENABLE_BIN([edbus-test-client], ["yes"])
+EFL_ENABLE_BIN([edbus-bluez-test], [${enable_ebluez}])
+EFL_ENABLE_BIN([edbus-connman0_7x-test], [${enable_econnman0_7x}])
+EFL_ENABLE_BIN([edbus-notification-daemon-test], [${enable_enotify}])
+EFL_ENABLE_BIN([edbus-notify-send], [${enable_enotify}])
+EFL_ENABLE_BIN([edbus-notify-test], [${enable_enotify}])
+EFL_ENABLE_BIN([edbus-ofono-test], [${enable_eofono}])
+EFL_ENABLE_BIN([edbus-ukit-test], [${enable_eukit}])
+EFL_ENABLE_BIN([edbus-performance-test], ["no"])
+EFL_ENABLE_BIN([edbus-async-test], ["yes"])
+
+if test "x${have_edbus_test}" = "xyes" ; then
+   PKG_CHECK_MODULES([EDBUS_TEST],
+      [ecore >= 1.6.99 dbus-1 >= 0.62],
+      [have_edbus_test="yes"],
+      [have_edbus_test="no"])
+fi
+
+if test "x${have_edbus_test_client}" = "xyes" ; then
+   PKG_CHECK_MODULES([EDBUS_TEST_CLIENT],
+      [ecore >= 1.6.99 dbus-1 >= 0.62],
+      [have_edbus_test_client="yes"],
+      [have_edbus_test_client="no"])
+fi
+
+if test "x${have_edbus_bluez_test}" = "xyes" ; then
+   PKG_CHECK_MODULES([EDBUS_BLUEZ_TEST],
+      [ecore >= 1.6.99 eina >= 1.6.99 dbus-1 >= 0.62],
+      [have_edbus_bluez_test="yes"],
+      [have_edbus_bluez_test="no"])
+fi
+
+if test "x${have_edbus_connman0_7x_test}" = "xyes" ; then
+   PKG_CHECK_MODULES([EDBUS_CONNMAN0_7X_TEST],
+      [ecore >= 1.6.99 eina >= 1.6.99 dbus-1 >= 0.62],
+      [have_edbus_connman0_7x_test="yes"],
+      [have_edbus_connman0_7x_test="no"])
+fi
+
+if test "x${have_edbus_notification_daemon_test}" = "xyes" ; then
+   PKG_CHECK_MODULES([EDBUS_NOTIFICATION_DAEMON_TEST],
+      [ecore >= 1.6.99 evas >= 1.6.99 eina >= 1.6.99 dbus-1 >= 0.62],
+      [have_edbus_notification_daemon_test="yes"],
+      [have_edbus_notification_daemon_test="no"])
+fi
+
+if test "x${have_edbus_notify_send}" = "xyes" ; then
+   PKG_CHECK_MODULES([EDBUS_NOTIFY_SEND],
+      [ecore >= 1.6.99 evas >= 1.6.99 eina >= 1.6.99 dbus-1 >= 0.62],
+      [have_edbus_notify_send="yes"],
+      [have_edbus_notify_send="no"])
+fi
+
+if test "x${have_edbus_notify_test}" = "xyes" ; then
+   PKG_CHECK_MODULES([EDBUS_NOTIFY_TEST],
+      [ecore >= 1.6.99 ecore-evas >= 1.6.99 evas >= 1.6.99 eina >= 1.6.99 dbus-1 >= 0.62],
+      [have_edbus_notify_test="yes"],
+      [have_edbus_notify_test="no"])
+fi
+
+if test "x${have_edbus_ofono_test}" = "xyes" ; then
+   PKG_CHECK_MODULES([EDBUS_OFONO_TEST],
+      [ecore >= 1.6.99 eina >= 1.6.99 dbus-1 >= 0.62],
+      [have_edbus_ofono_test="yes"],
+      [have_edbus_ofono_test="no"])
+fi
+
+if test "x${have_edbus_ukit_test}" = "xyes" ; then
+   PKG_CHECK_MODULES([EDBUS_UKIT_TEST],
+      [ecore >= 1.6.99 eina >= 1.6.99 dbus-1 >= 0.62],
+      [have_edbus_ukit_test="yes"],
+      [have_edbus_ukit_test="no"])
+fi
+
+if test "x${have_edbus_performance_test}" = "xyes" ; then
+   PKG_CHECK_MODULES([EDBUS_PERFORMANCE_TEST],
+      [ecore >= 1.6.99 eina >= 1.6.99 dbus-1 >= 0.62 ecore-evas >= 1.6.99 elementary >= 1.6.99 evas >= 1.6.99],
+      [have_edbus_performance_test="yes"],
+      [have_edbus_performance_test="no"])
+fi
+
+AM_CONDITIONAL([BUILD_EDBUS_PERFORMANCE_TEST], [test "x${have_edbus_performance_test}" = "xyes"])
+
+if test "x${have_edbus_async_test}" = "xyes" ; then
+   PKG_CHECK_MODULES([EDBUS_ASYNC_TEST],
+      [ecore >= 1.6.99 dbus-1 >= 0.62],
+      [have_edbus_async_test="yes"],
+      [have_edbus_async_test="no"])
+fi
+
+### Checks for header files
+
+
+### Checks for types
+
+
+### Checks for structures
+
+
+### Checks for compiler characteristics
+
+EFL_EDBUS_BUILD=""
+case "$host_os" in
+   mingw*)
+      EFL_EDBUS_BUILD="-DEFL_EDBUS_BUILD"
+   ;;
+esac
+AC_SUBST(EFL_EDBUS_BUILD)
+
+AC_HEADER_STDC
+AC_C___ATTRIBUTE__
+
+if ! test "x${VMIC}" = "x" ; then
+   EFL_COMPILER_FLAG([-Wall])
+   EFL_COMPILER_FLAG([-W])
+fi
+
+EFL_COMPILER_FLAG([-Wshadow])
+
+
+### Checks for linker characteristics
+
+lt_enable_auto_import=""
+case "$host_os" in
+   mingw*)
+      lt_enable_auto_import="-Wl,--enable-auto-import"
+   ;;
+esac
+AC_SUBST(lt_enable_auto_import)
+
+
+### Checks for library functions
+
+AC_FUNC_ALLOCA
+
+
+AC_SUBST(requirement_ebluez)
+AC_SUBST(requirement_econnman0_7x)
+AC_SUBST(requirement_edbus)
+AC_SUBST(requirement_ehal)
+AC_SUBST(requirement_enotify)
+AC_SUBST(requirement_eofono)
+AC_SUBST(requirement_eukit)
+AC_SUBST(requirement_dbus)
+
+AC_OUTPUT([
+e_dbus.spec
+Makefile
+doc/Makefile
+doc/Doxyfile
+src/Makefile
+src/lib/Makefile
+src/lib/bluez/Makefile
+src/lib/connman0_7x/Makefile
+src/lib/dbus/Makefile
+src/lib/hal/Makefile
+src/lib/notification/Makefile
+src/lib/ofono/Makefile
+src/lib/ukit/Makefile
+src/bin/Makefile
+ebluez.pc
+econnman-0.7x.pc
+edbus.pc
+ehal.pc
+enotify.pc
+eofono.pc
+eukit.pc
+])
+
+
+#####################################################################
+## Info
+
+echo
+echo
+echo
+echo "------------------------------------------------------------------------"
+echo "$PACKAGE $VERSION"
+echo "------------------------------------------------------------------------"
+echo
+echo "Configuration Options Summary:"
+echo
+echo "  Modules:"
+echo
+echo "    EBluez.............: $enable_ebluez"
+echo "    EConnman (0.7x)....: $enable_econnman0_7x"
+echo "    EHal...............: $enable_ehal"
+echo "    ENotify............: $enable_enotify"
+echo "    EOfono.............: $enable_eofono"
+echo "    EUkit..............: $enable_eukit"
+echo
+echo "  Binaries:"
+echo
+echo "    EDbus test.........: $have_edbus_test"
+echo "    EDbus client test..: $have_edbus_test_client"
+echo "    EDbus async test...: $have_edbus_async_test"
+echo "    EDbus performance..: $have_edbus_performance_test"
+echo "    EBluez test........: $have_edbus_bluez_test"
+echo "    EConnman (0.7x)test: $have_edbus_connman0_7x_test"
+echo "    ENotify Daemon test: $have_edbus_notification_daemon_test"
+echo "    ENotify send.......: $have_edbus_notify_send"
+echo "    ENotify test.......: $have_edbus_notify_test"
+echo "    EOfono test........: $have_edbus_ofono_test"
+echo "    EUkit test.........: $have_edbus_ukit_test"
+echo
+echo "Documentation..........: ${build_doc}"
+echo
+echo "Compilation............: make (or gmake)"
+echo "  CPPFLAGS.............: $CPPFLAGS"
+echo "  CFLAGS...............: $CFLAGS"
+echo "  LDFLAGS..............: $LDFLAGS"
+echo
+echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')"
+echo "  prefix...............: $prefix"
+echo
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644 (file)
index 0000000..0572ae9
--- /dev/null
@@ -0,0 +1,1679 @@
+# Doxyfile 1.7.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = e_dbus
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = @PACKAGE_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description for a project that appears at the top of each page and should give viewer a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = YES
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        = ../src/
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = YES
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = YES
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even if there is only one candidate or it is obvious which candidate to choose by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           = e_dbus_doxy_warnings.txt
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = @top_srcdir@/src/lib
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             = @top_srcdir@/doc/images/
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 2
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = e_ E_
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            = @srcdir@/head.html
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            = @srcdir@/foot.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = @srcdir@/e.css
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = YES
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET        = YES
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.enlightenment.EDbus
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.enlightenment.EDbus
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Enlightenment
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = org.enlightenment.EDbus
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+#  will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID         = org.enlightenment.EDbus
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = YES
+
+# This tag can be used to set the number of enum values (range [0,1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+# Note that a value of 0 will completely suppress the enum values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 1
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the mathjax.org site, so you can quickly see the result without installing
+# MathJax, but it is strongly recommended to install a local copy of MathJax
+# before deployment.
+
+MATHJAX_RELPATH        = http://www.mathjax.org/mathjax
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = __UNUSED__=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will write a font called Helvetica to the output
+# directory and reference it in all dot files that doxygen generates.
+# When you want a differently looking font you can specify the font name
+# using DOT_FONTNAME. You need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, svg, gif or svg.
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..881eb10
--- /dev/null
@@ -0,0 +1,32 @@
+MAINTAINERCLEANFILES = Makefile.in e_dbus_doxy_warnings.txt
+
+.PHONY: doc
+
+PACKAGE_DOCNAME = $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-doc
+
+if EFL_BUILD_DOC
+
+doc-clean:
+       rm -rf html/ latex/ $(top_builddir)/$(PACKAGE_DOCNAME).tar*
+
+doc: all
+       $(efl_doxygen)
+       cp $(srcdir)/images/* html/
+       rm -rf $(PACKAGE_DOCNAME).tar*
+       mkdir -p $(PACKAGE_DOCNAME)/doc
+       cp -R html/ latex/ $(PACKAGE_DOCNAME)/doc
+       tar cf $(PACKAGE_DOCNAME).tar $(PACKAGE_DOCNAME)/
+       bzip2 -9 $(PACKAGE_DOCNAME).tar
+       rm -rf $(PACKAGE_DOCNAME)/
+       mv $(PACKAGE_DOCNAME).tar.bz2 $(top_builddir)
+
+clean-local: doc-clean
+
+else
+
+doc:
+       @echo "Documentation not built. Run ./configure --help"
+
+endif
+
+EXTRA_DIST = Doxyfile.in $(wildcard images/*.*) e.css head.html foot.html
diff --git a/doc/e.css b/doc/e.css
new file mode 100644 (file)
index 0000000..8697a3a
--- /dev/null
+++ b/doc/e.css
@@ -0,0 +1,218 @@
+/*
+    Author:
+        Andres Blanc <andresblanc@gmail.com>
+       DaveMDS Andreoli <dave@gurumeditation.it>
+
+    Supported Browsers:
+        ie7, opera9, konqueror4 and firefox3
+
+        Please use a different file for ie6, ie5, etc. hacks.
+*/
+
+
+/* Necessary to place the footer at the bottom of the page */
+html, body {
+       height: 100%;
+       margin: 0px;
+       padding: 0px;
+}
+
+#container {
+       min-height: 100%;
+       height: auto !important;
+       height: 100%;
+       margin: 0 auto -53px;
+}
+
+#footer, #push {
+       height: 53px;
+}
+
+
+* html #container {
+       height: 100%;
+}
+
+/* Prevent floating elements overflowing containers */
+.clear {
+       clear: both;
+       width: 0px;
+       height: 0px;
+}
+
+/* Flexible & centered layout from 750 to 960 pixels */
+.layout {
+       max-width: 960px;
+       min-width: 760px;
+       margin-left: auto;
+       margin-right: auto;
+}
+
+body {
+       /*font-family: Lucida Grande, Helvetica, sans-serif;*/
+       font-family: "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif
+}
+
+/* Prevent design overflowing the viewport in small resolutions */
+#container {
+       padding-right: 17px;
+       padding-left: 17px;
+       background-image: url(head_bg.png);
+       background-repeat: repeat-x;
+}
+
+#header {
+       width: 100%;
+       height: 102px;
+}
+
+#header h1 {
+       width: 63px;
+       height: 63px;
+       background-image: url(e.png);
+       background-repeat: no-repeat;
+       position: absolute;
+       margin: 0px;
+}
+
+#header h1 span {
+       display: none;
+}
+
+#header h2 {
+       display: none;
+}
+
+/* .menu-container is used to set properties common to .menu and .submenu */
+#header .menu-container {
+}
+
+#header .menu-container ul {
+       list-style-type: none;
+       list-style-position: inside;
+       margin: 0;
+}
+
+#header .menu-container li {
+       display: block;
+       float: right;
+}
+
+#header .menu {
+       height: 63px;
+       display: block;
+       background-image: url(menu_bg.png);
+       background-repeat: repeat-x;
+}
+
+#header .menu ul {
+       height: 100%;
+       display: block;
+       background-image: url(menu_bg_last.png);
+       background-repeat: no-repeat;
+       background-position: top right;
+       padding-right: 17px;
+}
+
+#header .menu li {
+       height: 100%;
+       text-align: center;
+       background-image: url(menu_bg_unsel.png);
+       background-repeat: no-repeat;
+}
+
+#header .menu a {
+       height: 100%;
+       display: block;
+       color: #cdcdcd;
+       text-decoration: none;
+       font-size: 10pt;
+       line-height: 59px;
+       text-align: center;
+       padding: 0px 15px 0px 15px;
+}
+
+#header .menu li:hover {
+       background-image: url(menu_bg_hover.png);
+       background-repeat: no-repeat;
+}
+
+#header .menu li:hover a {
+       color: #FFFFFF;
+}
+
+#header .menu li.current {
+       background-image: url(menu_bg_current.png);
+       background-repeat: no-repeat;
+}
+
+#header .menu li.current a {
+       color: #646464;
+}
+
+
+/* Hide all the submenus but the current */
+#header .submenu ul {
+       display: none;
+}
+
+#header .submenu .current {
+       display: block;
+}
+
+#header .submenu {
+       font: bold 10px verdana,'Bitstream Vera Sans',helvetica,arial,sans-serif;
+       margin-top: 10px;
+}
+
+#header .submenu a {
+       color: #888888;
+       text-decoration: none;
+       font-size: 0.9em;
+       line-height: 15px;
+       padding:0px 5px 0px 5px;
+}
+
+#header .submenu a:hover {
+       color: #444444;
+}
+
+#header .submenu li {
+       border-left: 1px solid #DDDDDD;
+}
+
+#header .submenu li:last-child {
+       border-left: 0;
+}
+
+#header .doxytitle {
+       position: absolute;
+       font-size: 1.8em;
+       font-weight: bold;
+       color: #444444;
+       line-height: 35px;
+}
+
+#header small {
+       font-size: 0.4em;
+}
+
+#footer {
+       background-image: url(foot_bg.png);
+       width: 100%;
+}
+
+#footer table {
+       width: 100%;
+       text-align: center;
+       white-space: nowrap;
+       padding: 5px 30px 5px 30px;
+       font-size: 0.8em;
+       font-family: "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif;
+       color: #888888;
+}
+
+#footer td.copyright {
+       width: 100%;
+}
+
diff --git a/doc/foot.html b/doc/foot.html
new file mode 100644 (file)
index 0000000..78ef911
--- /dev/null
@@ -0,0 +1,19 @@
+ <div id="push"></div>
+ </div> <!-- #content -->
+  </div> <!-- .layout -->
+ </div> <!-- #container -->
+  <div id="footer">
+    <table><tr>
+      <td class="poweredby"><img src="doxygen.png"></td>
+      <td class="copyright">Copyright &copy;$year Enlightenment</td>
+      <td class="generated">Docs generated $datetime</td>
+    </tr></table>
+  </div>
+
+
+</body>
+</html>
diff --git a/doc/head.html b/doc/head.html
new file mode 100644 (file)
index 0000000..1293f78
--- /dev/null
@@ -0,0 +1,67 @@
+<html>
+<head>
+    <title>$title</title>
+    <meta http-equiv="content-type" content="text/html;charset=UTF-8">
+    <meta name="author" content="Andres Blanc" >
+    
+    <link rel="icon" href="images/favicon.png" type="image/x-icon">
+    <link rel="shortcut icon" href="images/favicon.png" type="image/x-icon">
+    <link rel="icon" href="images/favicon.png" type="image/ico">
+    <link rel="shortcut icon" href="images/favicon.png" type="image/ico">
+
+    <link rel="stylesheet" type="text/css" media="screen" href="e.css">
+    <link rel="stylesheet" type="text/css" media="screen" href="edoxy.css">
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="header">
+<div class="layout">
+    
+    <h1><span>Enlightenment</span></h1>
+    <h2><span>Beauty at your fingertips</span></h2>
+
+    <div class="menu-container">
+        <div class="menu">
+            <ul>
+               <li class="current"><a href="http://web.enlightenment.org/p.php?p=docs">Docs</a></li>
+                <li><a href="http://trac.enlightenment.org/e">Tracker</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=contact">Contact</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=contribute">Contribute</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=support">Support</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=download">Download</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=about">About</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=news">News</a></li>
+                <li><a href="http://www.enlightenment.org/">Home</a></li>
+            </ul>
+        </div>
+    </div>
+
+    <div class="doxytitle">
+        $projectname Documentation <small>at $date</small>
+    </div>
+
+    <div class="menu-container">
+        <div class="submenu">
+            <ul class="current">
+                <li><a href="group__EUkit__Group.html">EUkit</a></li>
+                <li><a href="group__EOfono__Group.html">EOfono</a></li>
+                <li><a href="group__ENotify__Group.html">ENotify</a></li>
+                <li><a href="group__EHal__Group.html">EHal</a></li>
+                <li><a href="group__EConnman__Group.html">EConnman</a></li>
+                <li><a href="group__EBluez__Group.html">EBluez</a></li>
+                <li><a href="group__EDbus__Group.html">EDbus</a></li>
+               <li class="current"><a  href="index.html">Main Page</a></li>
+            </ul>
+        </div>
+    </div>
+
+
+    <div class="clear"></div>
+</div>
+</div>
+
+<div id="content">
+<div class="layout">
diff --git a/doc/images/e.png b/doc/images/e.png
new file mode 100644 (file)
index 0000000..b3884a5
Binary files /dev/null and b/doc/images/e.png differ
diff --git a/doc/images/edoxy.css b/doc/images/edoxy.css
new file mode 100644 (file)
index 0000000..3caf7a9
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * This file contain a custom doxygen style to match e.org graphics
+ */
+
+
+
+/* BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
+       font-family: Geneva, Arial, Helvetica, sans-serif;
+}*/ 
+BODY, TD {
+       font-size: 12px;
+}
+H1 {
+       text-align: center;
+       font-size: 160%;
+}
+H2 {
+       font-size: 120%;
+}
+H3 {
+       font-size: 100%;
+}
+CAPTION { 
+       font-weight: bold 
+}
+DIV.qindex {
+       width: 100%;
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       padding: 2px;
+       line-height: 140%;
+}
+DIV.navpath {
+       width: 100%;
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       padding: 2px;
+       line-height: 140%;
+}
+DIV.navtab {
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       margin-right: 15px;
+       padding: 2px;
+}
+TD.navtab {
+       font-size: 70%;
+}
+A.qindex {
+       text-decoration: none;
+       font-weight: bold;
+       color: #1A419D;
+}
+A.qindex:visited {
+       text-decoration: none;
+       font-weight: bold;
+       color: #1A419D
+}
+A.qindex:hover {
+       text-decoration: none;
+       background-color: #ddddff;
+}
+A.qindexHL {
+       text-decoration: none;
+       font-weight: bold;
+       background-color: #6666cc;
+       color: #ffffff;
+       border: 1px double #9295C2;
+}
+A.qindexHL:hover {
+       text-decoration: none;
+       background-color: #6666cc;
+       color: #ffffff;
+}
+A.qindexHL:visited { 
+       text-decoration: none; 
+       background-color: #6666cc; 
+       color: #ffffff 
+}
+A.el { 
+       text-decoration: none; 
+       font-weight: bold 
+}
+A.elRef { 
+       font-weight: bold 
+}
+A.code:link { 
+       text-decoration: none; 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.code:visited { 
+       text-decoration: none; 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.codeRef:link { 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.codeRef:visited { 
+       font-weight: normal; 
+       color: #0000FF
+}
+A:hover, A:visited:hover { 
+       text-decoration: none;  
+       /* background-color: #f2f2ff; */
+       color: #000055;
+}
+A.anchor {
+       color: #000;
+}
+DL.el { 
+       margin-left: -1cm 
+}
+.fragment {
+       font-family: monospace, fixed;
+       font-size: 95%;
+}
+PRE.fragment {
+       border: 1px solid #CCCCCC;
+       background-color: #f5f5f5;
+       margin-top: 4px;
+       margin-bottom: 4px;
+       margin-left: 2px;
+       margin-right: 8px;
+       padding-left: 6px;
+       padding-right: 6px;
+       padding-top: 4px;
+       padding-bottom: 4px;
+}
+DIV.ah { 
+       background-color: black; 
+       font-weight: bold; 
+       color: #ffffff; 
+       margin-bottom: 3px; 
+       margin-top: 3px 
+}
+
+DIV.groupHeader {
+       margin-left: 16px;
+       margin-top: 12px;
+       margin-bottom: 6px;
+       font-weight: bold;
+}
+DIV.groupText { 
+       margin-left: 16px; 
+       font-style: italic; 
+       font-size: 90% 
+}
+/*BODY {
+       background: white;
+       color: black;
+       margin-right: 20px;
+       margin-left: 20px;
+}*/
+TD.indexkey {
+       background-color: #e8eef2;
+       font-weight: bold;
+       padding-right  : 10px;
+       padding-top    : 2px;
+       padding-left   : 10px;
+       padding-bottom : 2px;
+       margin-left    : 0px;
+       margin-right   : 0px;
+       margin-top     : 2px;
+       margin-bottom  : 2px;
+       border: 1px solid #CCCCCC;
+}
+TD.indexvalue {
+       background-color: #e8eef2;
+       font-style: italic;
+       padding-right  : 10px;
+       padding-top    : 2px;
+       padding-left   : 10px;
+       padding-bottom : 2px;
+       margin-left    : 0px;
+       margin-right   : 0px;
+       margin-top     : 2px;
+       margin-bottom  : 2px;
+       border: 1px solid #CCCCCC;
+}
+TR.memlist {
+       background-color: #f0f0f0; 
+}
+P.formulaDsp { 
+       text-align: center; 
+}
+IMG.formulaDsp {
+}
+IMG.formulaInl { 
+       vertical-align: middle; 
+}
+SPAN.keyword       { color: #008000 }
+SPAN.keywordtype   { color: #604020 }
+SPAN.keywordflow   { color: #e08000 }
+SPAN.comment       { color: #800000 }
+SPAN.preprocessor  { color: #806020 }
+SPAN.stringliteral { color: #002080 }
+SPAN.charliteral   { color: #008080 }
+SPAN.vhdldigit     { color: #ff00ff }
+SPAN.vhdlchar      { color: #000000 }
+SPAN.vhdlkeyword   { color: #700070 }
+SPAN.vhdllogic     { color: #ff0000 }
+
+.mdescLeft {
+       padding: 0px 8px 4px 8px;
+       font-size: 80%;
+       font-style: italic;
+       background-color: #FAFAFA;
+       border-top: 1px none #E0E0E0;
+       border-right: 1px none #E0E0E0;
+       border-bottom: 1px none #E0E0E0;
+       border-left: 1px none #E0E0E0;
+       margin: 0px;
+}
+.mdescRight {
+        padding: 0px 8px 4px 8px;
+       font-size: 80%;
+       font-style: italic;
+       background-color: #FAFAFA;
+       border-top: 1px none #E0E0E0;
+       border-right: 1px none #E0E0E0;
+       border-bottom: 1px none #E0E0E0;
+       border-left: 1px none #E0E0E0;
+       margin: 0px;
+}
+.memItemLeft {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memItemRight {
+       padding: 1px 8px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplItemLeft {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: none;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplItemRight {
+       padding: 1px 8px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: none;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplParams {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       color: #606060;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.search { 
+       color: #003399;
+       font-weight: bold;
+}
+FORM.search {
+       margin-bottom: 0px;
+       margin-top: 0px;
+}
+INPUT.search { 
+       font-size: 75%;
+       color: #000080;
+       font-weight: normal;
+       background-color: #e8eef2;
+}
+TD.tiny { 
+       font-size: 75%;
+}
+a {
+       color: #1A41A8;
+}
+a:visited {
+       color: #2A3798;
+}
+.dirtab { 
+       padding: 4px;
+       border-collapse: collapse;
+       border: 1px solid #84b0c7;
+}
+TH.dirtab { 
+       background: #e8eef2;
+       font-weight: bold;
+}
+HR { 
+       height: 1px;
+       border: none;
+       border-top: 1px solid black;
+}
+
+/* Style for detailed member documentation */
+.memtemplate {
+       font-size: 80%;
+       color: #606060;
+       font-weight: normal;
+       margin-left: 3px;
+} 
+.memnav { 
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       margin-right: 15px;
+       padding: 2px;
+}
+.memitem {
+       padding: 4px;
+       background-color: #eef3f5;
+       border-width: 1px;
+       border-style: solid;
+       border-color: #dedeee;
+       -moz-border-radius: 8px 8px 8px 8px;
+}
+.memname {
+       white-space: nowrap;
+       font-weight: bold;
+}
+.memdoc{
+       padding-left: 10px;
+}
+.memproto {
+       background-color: #d5e1e8;
+       width: 100%;
+       border-width: 1px;
+       border-style: solid;
+       border-color: #84b0c7;
+       font-weight: bold;
+       -moz-border-radius: 8px 8px 8px 8px;
+}
+.paramkey {
+       text-align: right;
+}
+.paramtype {
+       white-space: nowrap;
+}
+.paramname {
+       color: #602020;
+       font-style: italic;
+       white-space: nowrap;
+}
+/* End Styling for detailed member documentation */
+
+/* for the tree view */
+.ftvtree {
+       font-family: sans-serif;
+       margin:0.5em;
+}
+/* these are for tree view when used as main index */
+.directory { 
+       font-size: 9pt; 
+       font-weight: bold; 
+}
+.directory h3 { 
+       margin: 0px; 
+       margin-top: 1em; 
+       font-size: 11pt; 
+}
+
+/* The following two styles can be used to replace the root node title */
+/* with an image of your choice.  Simply uncomment the next two styles, */
+/* specify the name of your image and be sure to set 'height' to the */
+/* proper pixel height of your image. */
+
+/* .directory h3.swap { */
+/*     height: 61px; */
+/*     background-repeat: no-repeat; */
+/*     background-image: url("yourimage.gif"); */
+/* } */
+/* .directory h3.swap span { */
+/*     display: none; */
+/* } */
+
+.directory > h3 { 
+       margin-top: 0; 
+}
+.directory p { 
+       margin: 0px; 
+       white-space: nowrap; 
+}
+.directory div { 
+       display: none; 
+       margin: 0px; 
+}
+.directory img { 
+       vertical-align: -30%; 
+}
+/* these are for tree view when not used as main index */
+.directory-alt { 
+       font-size: 100%; 
+       font-weight: bold; 
+}
+.directory-alt h3 { 
+       margin: 0px; 
+       margin-top: 1em; 
+       font-size: 11pt; 
+}
+.directory-alt > h3 { 
+       margin-top: 0; 
+}
+.directory-alt p { 
+       margin: 0px; 
+       white-space: nowrap; 
+}
+.directory-alt div { 
+       display: none; 
+       margin: 0px; 
+}
+.directory-alt img { 
+       vertical-align: -30%; 
+}
+
diff --git a/doc/images/foot_bg.png b/doc/images/foot_bg.png
new file mode 100644 (file)
index 0000000..b24f3a4
Binary files /dev/null and b/doc/images/foot_bg.png differ
diff --git a/doc/images/head_bg.png b/doc/images/head_bg.png
new file mode 100644 (file)
index 0000000..081dc13
Binary files /dev/null and b/doc/images/head_bg.png differ
diff --git a/doc/images/menu_bg.png b/doc/images/menu_bg.png
new file mode 100644 (file)
index 0000000..e978743
Binary files /dev/null and b/doc/images/menu_bg.png differ
diff --git a/doc/images/menu_bg_current.png b/doc/images/menu_bg_current.png
new file mode 100644 (file)
index 0000000..de97c92
Binary files /dev/null and b/doc/images/menu_bg_current.png differ
diff --git a/doc/images/menu_bg_hover.png b/doc/images/menu_bg_hover.png
new file mode 100644 (file)
index 0000000..3fd851d
Binary files /dev/null and b/doc/images/menu_bg_hover.png differ
diff --git a/doc/images/menu_bg_last.png b/doc/images/menu_bg_last.png
new file mode 100644 (file)
index 0000000..88c116c
Binary files /dev/null and b/doc/images/menu_bg_last.png differ
diff --git a/doc/images/menu_bg_unsel.png b/doc/images/menu_bg_unsel.png
new file mode 100644 (file)
index 0000000..50e5fd8
Binary files /dev/null and b/doc/images/menu_bg_unsel.png differ
diff --git a/e_dbus.spec.in b/e_dbus.spec.in
new file mode 100644 (file)
index 0000000..56545e8
--- /dev/null
@@ -0,0 +1,67 @@
+%define _missing_doc_files_terminate_build 0
+
+%{!?_rel:%{expand:%%global _rel 0.enl%{?dist}}}
+
+Summary: EFL Wrapper for DBus
+Name: @PACKAGE@
+Version: @VERSION@
+Release: %{_rel}
+License: BSD
+Group: System Environment/Libraries
+URL: http://www.enlightenment.org/
+Source: %{name}-%{version}.tar.gz
+Packager: %{?_packager:%{_packager}}%{!?_packager:Michael Jennings <mej@eterm.org>}
+Vendor: %{?_vendorinfo:%{_vendorinfo}}%{!?_vendorinfo:The Enlightenment Project (http://www.enlightenment.org/)}
+Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}}
+Obsoletes: ecore-dbus <= 0.9.9.040
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+
+%description
+e_dbus provides a convenience wrapper for EFL applications using DBus.
+
+%package devel
+Summary: e_dbus headers, static libraries, documentation and test programs
+Group: System Environment/Libraries
+Requires: %{name} = %{version}
+
+%description devel
+Headers, static libraries, test programs and documentation for e_dbus
+
+%prep
+%setup -q
+
+%build
+%{configure} --prefix=%{_prefix}
+%{__make} %{?_smp_mflags} %{?mflags}
+
+%install
+%{__make} %{?mflags_install} DESTDIR=$RPM_BUILD_ROOT install
+
+# Get rid of unneeded testing cruft.
+%{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}
+
+%clean
+test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT
+
+%post
+/sbin/ldconfig
+
+%postun
+/sbin/ldconfig
+
+%files
+%defattr(-, root, root)
+%doc AUTHORS COPYING* README
+%{_bindir}/*
+%{_libdir}/*.so.*
+
+%files devel
+%defattr(-, root, root)
+%{_includedir}/e_dbus-1/*.h
+%{_includedir}/e_dbus-1/*/*.h
+%{_libdir}/*.so
+%{_libdir}/*.la
+%{_libdir}/*.a
+%{_libdir}/pkgconfig/*
+
+%changelog
diff --git a/ebluez.pc.in b/ebluez.pc.in
new file mode 100644 (file)
index 0000000..8630de5
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: ebluez
+Description: bluetooth device manager (bluez)
+@pkgconfig_requires_private@: @requirement_ebluez@
+Version: @VERSION@
+Libs: -L${libdir} -lebluez
+Cflags: -I${includedir}/e_dbus-@VMAJ@
diff --git a/econnman-0.7x.pc.in b/econnman-0.7x.pc.in
new file mode 100644 (file)
index 0000000..f3ba96a
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: econnman-0.7x
+Description: network connection manager (connman v0.7x)
+@pkgconfig_requires_private@: @requirement_econnman0_7x@
+Version: @VERSION@
+Libs: -L${libdir} -leconnman0_7x
+Cflags: -I${includedir}/e_dbus-@VMAJ@
diff --git a/edbus.pc.in b/edbus.pc.in
new file mode 100644 (file)
index 0000000..e3e368c
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: edbus
+Description: DBus convenience library
+@pkgconfig_requires_private@: @requirement_edbus@
+Version: @VERSION@
+Libs: -L${libdir} -ledbus @dbus_libs@
+Cflags: -I${includedir}/e_dbus-@VMAJ@
diff --git a/ehal.pc.in b/ehal.pc.in
new file mode 100644 (file)
index 0000000..c62f906
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: ehal
+Description: Hal convenience library
+@pkgconfig_requires_private@: @requirement_ehal@
+Version: @VERSION@
+Libs: -L${libdir} -lehal
+Cflags: -I${includedir}/e_dbus-@VMAJ@
diff --git a/enotify.pc.in b/enotify.pc.in
new file mode 100644 (file)
index 0000000..4219e9c
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: enotify
+Description: Notification convenience library
+@pkgconfig_requires_private@: @requirement_enotify@
+Version: @VERSION@
+Libs: -L${libdir} -lenotify
+Cflags: -I${includedir}/e_dbus-@VMAJ@
diff --git a/eofono.pc.in b/eofono.pc.in
new file mode 100644 (file)
index 0000000..bc2dc5f
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: eofono
+Description: oFono D-Bus wrappers
+@pkgconfig_requires_private@: @requirement_eofono@
+Version: @VERSION@
+Libs: -L${libdir} -leofono
+Cflags: -I${includedir}/e_dbus-@VMAJ@
diff --git a/eukit.pc.in b/eukit.pc.in
new file mode 100644 (file)
index 0000000..63df1d5
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: eukit
+Description: udisks/upower convenience library
+@pkgconfig_requires_private@: @requirement_eofono@
+Version: @VERSION@
+Libs: -L${libdir} -leukit
+Cflags: -I${includedir}/e_dbus-@VMAJ@
diff --git a/m4/ac_attribute.m4 b/m4/ac_attribute.m4
new file mode 100644 (file)
index 0000000..23479a9
--- /dev/null
@@ -0,0 +1,47 @@
+dnl Copyright (C) 2004-2008 Kim Woelders
+dnl Copyright (C) 2008 Vincent Torri <vtorri at univ-evry dot fr>
+dnl That code is public domain and can be freely used or copied.
+dnl Originally snatched from somewhere...
+
+dnl Macro for checking if the compiler supports __attribute__
+
+dnl Usage: AC_C___ATTRIBUTE__
+dnl call AC_DEFINE for HAVE___ATTRIBUTE__ and __UNUSED__
+dnl if the compiler supports __attribute__, HAVE___ATTRIBUTE__ is
+dnl defined to 1 and __UNUSED__ is defined to __attribute__((unused))
+dnl otherwise, HAVE___ATTRIBUTE__ is not defined and __UNUSED__ is
+dnl defined to nothing.
+
+AC_DEFUN([AC_C___ATTRIBUTE__],
+[
+
+AC_MSG_CHECKING([for __attribute__])
+
+AC_CACHE_VAL([ac_cv___attribute__],
+   [AC_TRY_COMPILE(
+       [
+#include <stdlib.h>
+
+int func(int x);
+int foo(int x __attribute__ ((unused)))
+{
+   exit(1);
+}
+       ],
+       [],
+       [ac_cv___attribute__="yes"],
+       [ac_cv___attribute__="no"]
+    )])
+
+AC_MSG_RESULT($ac_cv___attribute__)
+
+if test "x${ac_cv___attribute__}" = "xyes" ; then
+   AC_DEFINE([HAVE___ATTRIBUTE__], [1], [Define to 1 if your compiler has __attribute__])
+   AC_DEFINE([__UNUSED__], [__attribute__((unused))], [Macro declaring a function argument to be unused])
+  else
+    AC_DEFINE([__UNUSED__], [], [Macro declaring a function argument to be unused])
+fi
+
+])
+
+dnl End of ac_attribute.m4
diff --git a/m4/efl_binary.m4 b/m4/efl_binary.m4
new file mode 100644 (file)
index 0000000..0ad38ce
--- /dev/null
@@ -0,0 +1,78 @@
+dnl Copyright (C) 2010 Vincent Torri <vtorri at univ-evry dot fr>
+dnl That code is public domain and can be freely used or copied.
+
+dnl Macro that checks if a binary is built or not
+
+dnl Usage: EFL_ENABLE_BIN(binary, dep[, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Call AC_SUBST(BINARY_PRG) (BINARY is the uppercase of binary, - being transformed into _)
+dnl Define have_binary (- is transformed into _)
+dnl Define conditional BUILD_BINARY (BINARY is the uppercase of binary, - being transformed into _)
+
+AC_DEFUN([EFL_ENABLE_BIN],
+[
+
+m4_pushdef([UP], m4_translit([[$1]], [-a-z], [_A-Z]))dnl
+m4_pushdef([DOWN], m4_translit([[$1]], [-A-Z], [_a-z]))dnl
+
+dnl configure option
+
+AC_ARG_ENABLE([$1],
+   [AC_HELP_STRING([--disable-$1], [disable building of ]DOWN)],
+   [
+    if test "x${enableval}" = "xyes" ; then
+       have_[]m4_defn([DOWN])="yes"
+    else
+       have_[]m4_defn([DOWN])="no"
+    fi
+   ],
+   [have_[]m4_defn([DOWN])=$2])
+
+AC_MSG_CHECKING([whether to build ]DOWN[ binary])
+AC_MSG_RESULT([$have_[]m4_defn([DOWN])])
+
+if test "x$have_[]m4_defn([DOWN])" = "xyes"; then
+   UP[]_PRG=DOWN[${EXEEXT}]
+fi
+
+AC_SUBST(UP[]_PRG)
+
+AM_CONDITIONAL(BUILD_[]UP, test "x$have_[]m4_defn([DOWN])" = "xyes")
+
+AS_IF([test "x$have_[]m4_defn([DOWN])" = "xyes"], [$3], [$4])
+
+])
+
+dnl Macro that specifies the binary to be used
+
+dnl Usage: EFL_WITH_BIN(binary, package, msg)
+dnl Call AC_SUBST(BINARY_PRG) (BINARY is the uppercase of binary, - being transformed into _)
+dnl Define with_binary (- is transformed into _)
+dnl Define conditional BUILD_BINARY (BINARY is the uppercase of binary, - being transformed into _)
+
+AC_DEFUN([EFL_WITH_BIN],
+[
+
+m4_pushdef([UP], m4_translit([[$1]], [-a-z], [_A-Z]))dnl
+m4_pushdef([DOWN], m4_translit([[$1]], [-A-Z], [_a-z]))dnl
+
+AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+AC_MSG_NOTICE([$PKG_CONFIG])
+
+with_[]m4_defn([DOWN])=m4_esyscmd($PKG_CONFIG --variable=prefix $2)/bin/m4_defn([DOWN])
+
+dnl configure option
+
+AC_ARG_WITH([$1],
+   [AC_HELP_STRING([--with-$1-bin=PATH], [specify a specific path to ]DOWN)],
+   [
+    with_[]m4_defn([DOWN])=$withval
+    _efl_msg="( explicitely set)"
+   ])
+
+AC_MSG_NOTICE([$msg: ]m4_defn([DOWN])[$_efl_msg])
+
+AC_SUBST(with_[]m4_defn([DOWN]))
+
+AS_IF([test "x$have_[]m4_defn([DOWN])" = "xyes"], [$4], [$5])
+
+])
diff --git a/m4/efl_compiler_flag.m4 b/m4/efl_compiler_flag.m4
new file mode 100644 (file)
index 0000000..e3fc821
--- /dev/null
@@ -0,0 +1,24 @@
+dnl Checks if a given compiler switch is supported.
+dnl If so, this macro adds the flag to the CFLAGS
+
+AC_DEFUN([EFL_COMPILER_FLAG],
+[
+
+CFLAGS_save="${CFLAGS}"
+CFLAGS="${CFLAGS} $1"
+  
+AC_LANG_PUSH([C])
+AC_MSG_CHECKING([whether the compiler supports $1])
+
+AC_COMPILE_IFELSE(
+   [AC_LANG_PROGRAM([[]])],
+   [have_flag="yes"],
+   [have_flag="no"])
+AC_MSG_RESULT([${have_flag}])
+
+if test "x${have_flag}" = "xno" ; then
+   CFLAGS="${CFLAGS_save}"
+fi
+AC_LANG_POP([C])
+
+])
diff --git a/m4/efl_doxygen.m4 b/m4/efl_doxygen.m4
new file mode 100644 (file)
index 0000000..7324af3
--- /dev/null
@@ -0,0 +1,94 @@
+dnl Copyright (C) 2008 Vincent Torri <vtorri at univ-evry dot fr>
+dnl That code is public domain and can be freely used or copied.
+
+dnl Macro that check if doxygen is available or not.
+
+dnl EFL_CHECK_DOXYGEN([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for the doxygen program
+dnl Defines efl_doxygen
+dnl Defines the automake conditionnal EFL_BUILD_DOC
+dnl
+AC_DEFUN([EFL_CHECK_DOXYGEN],
+[
+
+dnl
+dnl Disable the build of the documentation
+dnl
+AC_ARG_ENABLE([doc],
+   [AC_HELP_STRING(
+       [--disable-doc],
+       [Disable documentation build @<:@default=enabled@:>@])],
+   [
+    if test "x${enableval}" = "xyes" ; then
+       efl_enable_doc="yes"
+    else
+       efl_enable_doc="no"
+    fi
+   ],
+   [efl_enable_doc="yes"])
+
+AC_MSG_CHECKING([whether to build documentation])
+AC_MSG_RESULT([${efl_enable_doc}])
+
+if test "x${efl_enable_doc}" = "xyes" ; then
+
+dnl Specify the file name, without path
+
+   efl_doxygen="doxygen"
+
+   AC_ARG_WITH([doxygen],
+      [AC_HELP_STRING(
+          [--with-doxygen=FILE],
+          [doxygen program to use @<:@default=doxygen@:>@])],
+
+dnl Check the given doxygen program.
+
+      [efl_doxygen=${withval}
+       AC_CHECK_PROG([efl_have_doxygen],
+          [${efl_doxygen}],
+          [yes],
+          [no])
+       if test "x${efl_have_doxygen}" = "xno" ; then
+          echo "WARNING:"
+          echo "The doxygen program you specified:"
+          echo "${efl_doxygen}"
+          echo "was not found.  Please check the path and make sure "
+          echo "the program exists and is executable."
+          AC_MSG_WARN([no doxygen detected. Documentation will not be built])
+       fi
+      ],
+      [AC_CHECK_PROG([efl_have_doxygen],
+          [${efl_doxygen}],
+          [yes],
+          [no])
+       if test "x${efl_have_doxygen}" = "xno" ; then
+          echo "WARNING:"
+          echo "The doxygen program was not found in your execute path."
+          echo "You may have doxygen installed somewhere not covered by your path."
+          echo ""
+          echo "If this is the case make sure you have the packages installed, AND"
+          echo "that the doxygen program is in your execute path (see your"
+          echo "shell manual page on setting the \$PATH environment variable), OR"
+          echo "alternatively, specify the program to use with --with-doxygen."
+          AC_MSG_WARN([no doxygen detected. Documentation will not be built])
+       fi
+      ])
+else
+   efl_have_doxygen="no"
+fi
+
+dnl
+dnl Substitution
+dnl
+AC_SUBST([efl_doxygen])
+
+if ! test "x${efl_have_doxygen}" = "xyes" ; then
+   efl_enable_doc="no"
+fi
+
+AM_CONDITIONAL(EFL_BUILD_DOC, test "x${efl_have_doxygen}" = "xyes")
+
+AS_IF([test "x$efl_have_doxygen" = "xyes"], [$1], [$2])
+])
+
+dnl End of efl_doxygen.m4
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..97baf85
--- /dev/null
@@ -0,0 +1,2 @@
+MAINTAINERCLEANFILES = Makefile.in
+SUBDIRS = lib bin
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
new file mode 100644 (file)
index 0000000..2041091
--- /dev/null
@@ -0,0 +1,207 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CFLAGS = \
+-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\"
+
+EDBUS_CPPFLAGS = @EDBUS_CFLAGS@
+
+bin_PROGRAMS =
+
+if BUILD_EDBUS_TEST
+bin_PROGRAMS += e_dbus_test
+endif
+
+if BUILD_EDBUS_TEST_CLIENT
+bin_PROGRAMS += e_dbus_test_client
+endif
+
+if BUILD_EDBUS_ASYNC_TEST
+bin_PROGRAMS += e_dbus_async_server_test
+bin_PROGRAMS += e_dbus_async_client_test
+endif
+
+if BUILD_EDBUS_BLUEZ_TEST
+bin_PROGRAMS += e_dbus_bluez_test
+endif
+
+if BUILD_EDBUS_CONNMAN0_7X_TEST
+bin_PROGRAMS += e_dbus_connman0_7x_test
+endif
+
+if BUILD_EDBUS_NOTIFICATION_DAEMON_TEST
+bin_PROGRAMS += e_dbus_notification_daemon
+endif
+
+if BUILD_EDBUS_NOTIFY_SEND
+bin_PROGRAMS += e-notify-send
+endif
+
+if BUILD_EDBUS_NOTIFY_TEST
+bin_PROGRAMS += e_dbus_notify
+endif
+
+if BUILD_EDBUS_OFONO_TEST
+bin_PROGRAMS += e_dbus_ofono_test
+endif
+
+if BUILD_EDBUS_UKIT_TEST
+bin_PROGRAMS += e_dbus_ukit_test
+endif
+
+if BUILD_EDBUS_PERFORMANCE_TEST
+bin_PROGRAMS += e_dbus_performance
+endif
+
+noinst_PROGRAMS =
+
+if BUILD_EDBUS_CONNMAN0_7X_TEST
+noinst_PROGRAMS += e_dbus_connman0_7x_test_api
+endif
+
+if BUILD_EDBUS_TEST
+e_dbus_test_SOURCES = test.c
+e_dbus_test_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/dbus \
+@EDBUS_TEST_CFLAGS@
+e_dbus_test_LDADD = \
+$(top_builddir)/src/lib/dbus/libedbus.la \
+@EDBUS_TEST_LIBS@
+endif
+
+if BUILD_EDBUS_TEST_CLIENT
+e_dbus_test_client_SOURCES = test_client.c
+e_dbus_test_client_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/dbus \
+@EDBUS_TEST_CLIENT_CFLAGS@
+e_dbus_test_client_LDADD = \
+$(top_builddir)/src/lib/dbus/libedbus.la \
+@EDBUS_TEST_CLIENT_LIBS@
+endif
+
+if BUILD_EDBUS_ASYNC_TEST
+e_dbus_async_server_test_SOURCES = async_server_test.c
+e_dbus_async_server_test_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/dbus \
+@EDBUS_ASYNC_TEST_CFLAGS@
+e_dbus_async_server_test_LDADD = \
+$(top_builddir)/src/lib/dbus/libedbus.la \
+@EDBUS_ASYNC_TEST_LIBS@
+
+e_dbus_async_client_test_SOURCES = async_client_test.c
+e_dbus_async_client_test_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/dbus \
+@EDBUS_ASYNC_TEST_CFLAGS@
+e_dbus_async_client_test_LDADD = \
+$(top_builddir)/src/lib/dbus/libedbus.la \
+@EDBUS_ASYNC_TEST_LIBS@
+endif
+
+if BUILD_EDBUS_BLUEZ_TEST
+e_dbus_bluez_test_SOURCES = e_dbus_bluez_test.c
+e_dbus_bluez_test_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/dbus \
+-I$(top_srcdir)/src/lib/bluez \
+@EDBUS_BLUEZ_TEST_CFLAGS@
+e_dbus_bluez_test_LDADD = \
+$(top_builddir)/src/lib/dbus/libedbus.la \
+$(top_builddir)/src/lib/bluez/libebluez.la \
+@EDBUS_BLUEZ_TEST_LIBS@
+endif
+
+if BUILD_EDBUS_CONNMAN0_7X_TEST
+e_dbus_connman0_7x_test_SOURCES = e_dbus_connman0_7x_test.c
+e_dbus_connman0_7x_test_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/dbus \
+-I$(top_srcdir)/src/lib \
+@EDBUS_CONNMAN0_7X_TEST_CFLAGS@
+e_dbus_connman0_7x_test_LDADD = \
+$(top_builddir)/src/lib/dbus/libedbus.la \
+$(top_builddir)/src/lib/connman0_7x/libeconnman0_7x.la \
+@EDBUS_CONNMAN0_7X_TEST_LIBS@
+
+e_dbus_connman0_7x_test_api_SOURCES = e_dbus_connman0_7x_test_api.c
+e_dbus_connman0_7x_test_api_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/dbus \
+-I$(top_srcdir)/src/lib \
+@EDBUS_CONNMAN0_7X_TEST_CFLAGS@
+e_dbus_connman0_7x_test_api_LDADD = \
+$(top_builddir)/src/lib/dbus/libedbus.la \
+$(top_builddir)/src/lib/connman0_7x/libeconnman0_7x.la \
+@EDBUS_CONNMAN0_7X_TEST_LIBS@
+endif
+
+ENOTIFY_LIBS = $(top_builddir)/src/lib/notification/libenotify.la
+
+if BUILD_EDBUS_NOTIFICATION_DAEMON_TEST
+e_dbus_notification_daemon_SOURCES = notification_daemon.c
+e_dbus_notification_daemon_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/dbus \
+-I$(top_srcdir)/src/lib/notification \
+@EDBUS_NOTIFICATION_DAEMON_TEST_CFLAGS@
+e_dbus_notification_daemon_LDADD = \
+$(ENOTIFY_LIBS) \
+$(top_builddir)/src/lib/dbus/libedbus.la \
+@EDBUS_NOTIFICATION_DAEMON_TEST_LIBS@
+endif
+
+if BUILD_EDBUS_NOTIFY_SEND
+e_notify_send_SOURCES = notify-send.c
+e_notify_send_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/dbus \
+-I$(top_srcdir)/src/lib/notification \
+@EDBUS_NOTIFY_SEND_CFLAGS@
+e_notify_send_LDADD = \
+$(ENOTIFY_LIBS) \
+$(top_builddir)/src/lib/dbus/libedbus.la \
+@EDBUS_NOTIFY_SEND_LIBS@
+endif
+
+if BUILD_EDBUS_NOTIFY_TEST
+EXTRA_DIST = logo.png
+logodir = $(datadir)/e_dbus
+logo_DATA = logo.png
+e_dbus_notify_SOURCES = notify.c
+e_dbus_notify_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/dbus \
+-I$(top_srcdir)/src/lib/notification \
+@EDBUS_NOTIFY_TEST_CFLAGS@
+e_dbus_notify_LDADD = \
+$(ENOTIFY_LIBS) \
+$(top_builddir)/src/lib/dbus/libedbus.la \
+@EDBUS_NOTIFY_TEST_LIBS@
+endif
+
+if BUILD_EDBUS_OFONO_TEST
+e_dbus_ofono_test_SOURCES = e_dbus_ofono_test.c
+e_dbus_ofono_test_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/dbus \
+-I$(top_srcdir)/src/lib/ofono \
+@EDBUS_OFONO_TEST_CFLAGS@
+e_dbus_ofono_test_LDADD = \
+$(top_builddir)/src/lib/dbus/libedbus.la \
+$(top_builddir)/src/lib/ofono/libeofono.la \
+@EDBUS_OFONO_TEST_LIBS@
+endif
+
+if BUILD_EDBUS_UKIT_TEST
+e_dbus_ukit_test_SOURCES = e_dbus_ukit_test.c
+e_dbus_ukit_test_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/dbus \
+-I$(top_srcdir)/src/lib/ukit \
+@EDBUS_UKIT_TEST_CFLAGS@
+e_dbus_ukit_test_LDADD = \
+$(top_builddir)/src/lib/dbus/libedbus.la \
+$(top_builddir)/src/lib/ukit/libeukit.la \
+@EDBUS_UKIT_TEST_LIBS@
+endif
+
+if BUILD_EDBUS_PERFORMANCE_TEST
+e_dbus_performance_SOURCES = performance.c
+e_dbus_performance_CFLAGS = \
+-I$(top_srcdir)/src/lib/dbus \
+@EDBUS_PERFORMANCE_TEST_CFLAGS@
+e_dbus_performance_LDADD = \
+$(top_builddir)/src/lib/dbus/libedbus.la \
+@EDBUS_PERFORMANCE_TEST_LIBS@
+endif
+
diff --git a/src/bin/async_client_test.c b/src/bin/async_client_test.c
new file mode 100644 (file)
index 0000000..04db1f5
--- /dev/null
@@ -0,0 +1,58 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <Ecore.h>
+#include "E_DBus.h"
+
+#define DBUS_NAME "com.profusion"
+#define OBJECT_PATH "/com/profusion/test"
+#define IFACE_NAME "com.Profusion.Test"
+
+static E_DBus_Connection *conn = NULL;
+
+static void
+_cb_resp(void *data, DBusMessage *msg, DBusError *error)
+{
+   DBusError new_error;
+   int size;
+
+   if (dbus_error_is_set(error))
+     {
+        printf("dbus error\nName: %s\nDescription: %s\n", error->name,
+               error->message);
+        ecore_main_loop_quit();
+        return;
+     }
+
+   dbus_error_init(&new_error);
+   dbus_message_get_args(msg, &new_error, DBUS_TYPE_INT32, &size,
+                         DBUS_TYPE_INVALID);
+   if (dbus_error_is_set(&new_error))
+     printf("dbus error\nName: %s\nDescription: %s\n", new_error.name,
+            new_error.message);
+   else printf("size = %d\n", size);
+
+   ecore_main_loop_quit();
+}
+
+int
+main(int argc, char *argv[])
+{
+   char *string = "lalala";
+   DBusMessage *msg;
+
+   e_dbus_init();
+   conn = e_dbus_bus_get(DBUS_BUS_SESSION);
+
+   msg = dbus_message_new_method_call(DBUS_NAME, OBJECT_PATH,
+                                      IFACE_NAME, "string_len_async");
+   dbus_message_append_args(msg, DBUS_TYPE_STRING, &string, DBUS_TYPE_INVALID);
+   e_dbus_message_send(conn, msg, _cb_resp, -1, NULL);
+   dbus_message_unref(msg);
+
+   ecore_main_loop_begin();
+
+   e_dbus_shutdown();
+   return 0;
+}
diff --git a/src/bin/async_server_test.c b/src/bin/async_server_test.c
new file mode 100644 (file)
index 0000000..3560e3b
--- /dev/null
@@ -0,0 +1,124 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <Ecore.h>
+#include "E_DBus.h"
+
+#define DBUS_NAME "com.profusion"
+#define OBJECT_PATH "/com/profusion/test"
+#define IFACE_NAME "com.Profusion.Test"
+
+static E_DBus_Connection *conn = NULL;
+static E_DBus_Object *obj_path = NULL;
+
+typedef struct _EDBus_Method
+  {
+     char *member;
+     char *signature;
+     char *reply_signature;
+     E_DBus_Method_Cb func;
+  } EDBus_Method;
+
+static void
+obj_register(char *path_name, char *iface_name, EDBus_Method *methods)
+{
+   obj_path = e_dbus_object_add(conn, path_name, NULL);
+   E_DBus_Interface *iface = e_dbus_interface_new(iface_name);
+   const EDBus_Method *_method;
+
+   e_dbus_object_interface_attach(obj_path, iface);
+   e_dbus_interface_unref(iface);
+
+   for (_method = methods; _method != NULL && _method->member != NULL; _method++)
+     e_dbus_interface_method_add(iface, _method->member,
+                                        _method->signature,
+                                        _method->reply_signature,
+                                        _method->func);
+}
+
+static void
+_dbus_error_check(DBusError *error)
+{
+   if (dbus_error_is_set(error))
+     {
+        printf("dbus error\nName: %s\nDescription: %s\n", error->name,
+               error->message);
+        ecore_main_loop_quit();
+     }
+}
+
+Eina_Bool
+_resp_async(void *data)
+{
+   DBusMessage *msg = data;
+   DBusMessage *reply;
+   DBusError new_err;
+   char *string;
+   int size;
+
+   dbus_error_init(&new_err);
+   dbus_message_get_args(msg, &new_err, DBUS_TYPE_STRING, &string,
+   DBUS_TYPE_INVALID);
+   _dbus_error_check(&new_err);
+
+   reply = dbus_message_new_method_return(msg);
+   size = strlen(string);
+   dbus_message_append_args(reply, DBUS_TYPE_INT32, &size, DBUS_TYPE_INVALID);
+   e_dbus_message_send(conn, reply, NULL, -1, NULL);
+
+   dbus_message_unref(msg);
+   dbus_message_unref(reply);
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static DBusMessage *
+_async(E_DBus_Object *obj, DBusMessage *msg)
+{
+   dbus_message_ref(msg);
+   printf("received a string_len_async call\n");
+   printf("response will be send in 5 seconds\n");
+   ecore_timer_add (5, _resp_async, msg);
+   return NULL;
+}
+
+static void
+_cb_dbus_request_name(void *context, DBusMessage *msg, DBusError *err)
+{
+   DBusError new_err;
+   dbus_uint32_t msgtype;
+   EDBus_Method table_methods[] =
+     {
+        { "string_len_async", "s", "d", _async},
+        { NULL, NULL, NULL, NULL }
+     };
+
+   _dbus_error_check(err);
+   dbus_error_init(&new_err);
+   dbus_message_get_args(msg, &new_err, DBUS_TYPE_UINT32, &msgtype,
+                         DBUS_TYPE_INVALID);
+   if (msgtype != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+     {
+        printf("Could not get the DBus name: reply=%d", msgtype);
+        ecore_main_loop_quit();
+     }
+
+   obj_register(OBJECT_PATH, IFACE_NAME, table_methods);
+}
+
+int
+main(int argc, char *argv[])
+{
+   e_dbus_init();
+
+   conn = e_dbus_bus_get(DBUS_BUS_SESSION);
+
+   e_dbus_request_name(conn, DBUS_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE,
+                       _cb_dbus_request_name, NULL);
+
+   ecore_main_loop_begin();
+
+   e_dbus_shutdown();
+   return 0;
+}
diff --git a/src/bin/e_dbus_bluez_test.c b/src/bin/e_dbus_bluez_test.c
new file mode 100644 (file)
index 0000000..d2f479e
--- /dev/null
@@ -0,0 +1,860 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "E_Bluez.h"
+
+typedef struct _E_Msgbus_Data E_Msgbus_Data;
+
+struct _E_Msgbus_Data {
+       E_DBus_Connection *conn;
+       E_DBus_Object     *obj;
+};
+
+static E_Msgbus_Data *_msgbus_data = NULL;
+
+static E_DBus_Interface *iface = NULL;
+
+static void
+_method_success_check(void *data, __UNUSED__ DBusMessage *msg, DBusError *error)
+{
+   const char *name = data;
+
+   if ((!error) || (!dbus_error_is_set(error)))
+     {
+       printf("SUCCESS: method %s() finished successfully.\n", name);
+       return;
+     }
+
+   printf("FAILURE: method %s() finished with error: %s %s\n",
+         name, error->name, error->message);
+   dbus_error_free(error);
+}
+
+static void
+_default_adapter_callback(__UNUSED__ void *data, DBusMessage *msg, __UNUSED__ DBusError *err)
+{
+   E_Bluez_Element *element;
+   const char *path;
+
+   if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                           DBUS_TYPE_INVALID) == EINA_FALSE)
+           printf("FAILURE: failed to get default adapter\n");
+
+   printf("SUCCESS: default adapter: %s\n", path);
+
+   element = e_bluez_element_get(path);
+   e_bluez_element_print(stdout, element);
+   return;
+
+}
+
+static void
+_create_paired_device_cb(void *data, DBusMessage *msg, DBusError *err)
+{
+       e_dbus_object_interface_detach(_msgbus_data->obj, iface);
+       e_dbus_object_free(_msgbus_data->obj);
+       e_dbus_interface_unref(iface);
+       _method_success_check(data, msg, err);
+}
+
+static DBusMessage*
+_request_pincode_cb(__UNUSED__ E_DBus_Object *obj, DBusMessage *msg)
+{
+       DBusMessage *reply;
+       char pin[16];
+       char *p = pin;
+       int ret;
+
+       printf("Enter PIN Code:\n");
+       ret = scanf("%15s", p);
+       if (ret != 1)
+               return NULL;
+
+       reply = dbus_message_new_method_return(msg);
+       dbus_message_append_args(reply, DBUS_TYPE_STRING, &p,
+                                DBUS_TYPE_INVALID);
+
+       return reply;
+}
+
+static void
+_elements_print(E_Bluez_Element **elements, unsigned int count)
+{
+   unsigned int i;
+   for (i = 0; i < count; i++)
+     {
+       printf("--- element %d:\n", i);
+       e_bluez_element_print(stdout, elements[i]);
+     }
+   free(elements);
+   printf("END: all elements count = %u\n", count);
+}
+
+static Eina_Bool
+_on_element_add(__UNUSED__ void *data, __UNUSED__ int type, void *info)
+{
+   E_Bluez_Element *element = info;
+   printf(">>> %s\n", element->path);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_element_del(__UNUSED__ void *data, __UNUSED__ int type, void *info)
+{
+   E_Bluez_Element *element = info;
+   printf("<<< %s\n", element->path);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_element_updated(__UNUSED__ void *data, __UNUSED__ int type, void *info)
+{
+   E_Bluez_Element *element = info;
+   printf("!!! %s\n", element->path);
+   e_bluez_element_print(stderr, element);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_device_found(__UNUSED__ void *data, int __UNUSED__ type, void *info)
+{
+   E_Bluez_Device_Found *device = info;
+   printf("!!! %s\n", device->adapter->path);
+   printf(":::DeviceFound %s\n", device->name);
+   e_bluez_element_array_print(stderr, device->array);
+   printf("\n");
+
+   e_bluez_devicefound_free(device);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_quit(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   fputs("Bye!\n", stderr);
+   ecore_main_loop_quit();
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_on_cmd_sync(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   e_bluez_manager_sync_elements();
+   return ECORE_CALLBACK_RENEW;
+}
+
+static char *
+_tok(char *p)
+{
+   p = strchr(p, ' ');
+   if (!p)
+     return NULL;
+
+   *p = '\0';
+   p++;
+   while (isspace(*p))
+     p++;
+   if (*p == '\0')
+     return NULL;
+
+   return p;
+}
+
+static Eina_Bool
+_on_cmd_get_all(__UNUSED__ char *cmd, char *args)
+{
+   E_Bluez_Element **elements;
+   char *type;
+   unsigned int count;
+   Eina_Bool ret;
+
+   if (!args)
+     type = NULL;
+   else
+     type = args;
+
+   if (type)
+     ret = e_bluez_elements_get_all_type(type, &count, &elements);
+   else
+     ret = e_bluez_elements_get_all(&count, &elements);
+
+   if (!ret)
+     fputs("ERROR: could not get elements\n", stderr);
+   else
+     {
+       printf("BEG: all elements type=%s count = %d\n", type, count);
+       _elements_print(elements, count);
+     }
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static E_Bluez_Element *
+_element_from_args(char *args, char **next_args)
+{
+   E_Bluez_Element *element;
+
+   if (!args)
+     {
+       fputs("ERROR: missing element path\n", stderr);
+       *next_args = NULL;
+       return NULL;
+     }
+
+   *next_args = _tok(args);
+   element = e_bluez_element_get(args);
+   if (!element)
+     fprintf(stderr, "ERROR: no element called \"%s\".\n", args);
+
+   return element;
+}
+
+static Eina_Bool
+_on_cmd_print(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+   if (element)
+     e_bluez_element_print(stdout, element);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_get_properties(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+   if (element)
+     e_bluez_element_properties_sync(element);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_property_set(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args, *name, *p;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+   void *value;
+   long vlong;
+   unsigned short vu16;
+   unsigned int vu32;
+   int type;
+
+   if (!element)
+     return ECORE_CALLBACK_RENEW;
+
+   if (!next_args)
+     {
+       fputs("ERROR: missing parameters name, type and value.\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   name = next_args;
+   p = _tok(name);
+   if (!p)
+     {
+       fputs("ERROR: missing parameters type and value.\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   next_args = _tok(p);
+   if (!next_args)
+     {
+       fputs("ERROR: missing parameter value.\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   type = p[0];
+   switch (type)
+     {
+      case DBUS_TYPE_BOOLEAN:
+        vlong = !!atol(next_args);
+        value = &vlong;
+        fprintf(stderr, "DBG: boolean is: %ld\n", vlong);
+        break;
+      case DBUS_TYPE_UINT16:
+        vu16 = strtol(next_args, &p, 0);
+        if (p == next_args)
+          {
+             fprintf(stderr, "ERROR: invalid number \"%s\".\n", next_args);
+             return ECORE_CALLBACK_RENEW;
+          }
+        value = &vu16;
+        fprintf(stderr, "DBG: u16 is: %hu\n", vu16);
+        break;
+      case DBUS_TYPE_UINT32:
+        vu32 = strtol(next_args, &p, 0);
+        if (p == next_args)
+          {
+             fprintf(stderr, "ERROR: invalid number \"%s\".\n", next_args);
+             return ECORE_CALLBACK_RENEW;
+          }
+        value = &vu32;
+        fprintf(stderr, "DBG: u16 is: %u\n", vu32);
+        break;
+      case DBUS_TYPE_STRING:
+      case DBUS_TYPE_OBJECT_PATH:
+        p = next_args + strlen(next_args);
+        if (p > next_args)
+          p--;
+        while (p > next_args && isspace(*p))
+          p--;
+        if (p <= next_args)
+          {
+             fprintf(stderr, "ERROR: invalid string \"%s\".\n", next_args);
+          }
+        p[1] = '\0';
+        value = next_args;
+        fprintf(stderr, "DBG: string is: \"%s\"\n", next_args);
+        break;
+      default:
+        fprintf(stderr, "ERROR: don't know how to parse type '%c' (%d)\n",
+                type, type);
+        return ECORE_CALLBACK_RENEW;
+     }
+
+   fprintf(stderr, "set_property %s [%p] %s %c %p...\n",
+          args, element, name, type, value);
+   if (!e_bluez_element_property_set(element, name, type, value))
+       fputs("ERROR: error setting property.\n", stderr);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+/* Manager Commands */
+
+static Eina_Bool
+_on_cmd_manager_get(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   E_Bluez_Element *element;
+   element = e_bluez_manager_get();
+   e_bluez_element_print(stderr, element);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_default_adapter(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   return e_bluez_manager_default_adapter(_default_adapter_callback, NULL);
+}
+
+/* Adapter Commands */
+
+static Eina_Bool
+_on_cmd_adapter_register_agent(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args, *path, *cap;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (!next_args) {
+          fputs("ERROR: missing parameters name, type and value.\n", stderr);
+          return ECORE_CALLBACK_RENEW;
+   }
+
+   path = next_args;
+   cap = _tok(path);
+   if (!cap) {
+          fputs("ERROR: missing parameters name, type and value.\n", stderr);
+          return ECORE_CALLBACK_RENEW;
+   }
+
+   if (e_bluez_adapter_agent_register(element,
+       path, cap, _method_success_check, "adapter_register_agent"))
+     printf(":::Registering agent %s (%s)...\n", path, cap);
+   else
+     fprintf(stderr, "ERROR: can't register agent %s\n", path);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_adapter_unregister_agent(__UNUSED__ char *cmd, char *args)
+{
+   char *path, *next_args;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the object path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   path = next_args;
+   if (e_bluez_adapter_agent_unregister(element,
+       path, _method_success_check, "adapter_unregister_agent"))
+     printf(":::Unregistering agent %s...\n", path);
+   else
+     fprintf(stderr, "ERROR: can't unregister agent %s\n", path);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_adapter_get_address(__UNUSED__ char *cmd, char *args)
+{
+   const char *address;
+   char *next_args;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (e_bluez_adapter_address_get(element, &address))
+     printf(":::Adapter address = \"%s\"\n", address);
+   else
+     fputs("ERROR: can't get adapter address\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_adapter_get_name(__UNUSED__ char *cmd, char *args)
+{
+   const char *name;
+   char *next_args;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (e_bluez_adapter_name_get(element, &name))
+     printf(":::Adapter name = \"%s\"\n", name);
+   else
+     fputs("ERROR: can't get adapter name\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_adapter_set_name(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (!next_args) {
+      fprintf(stderr, "ERROR: missing name value\n");
+      return ECORE_CALLBACK_RENEW;
+   }
+
+   if (e_bluez_adapter_name_set(element, next_args, _method_success_check,
+                          "adapter_set_name"))
+     printf(":::Adapter %s Name set to %s\n", element->path, next_args);
+   else
+     fputs("ERROR: can't set adapter name\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_adapter_get_powered(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args;
+   Eina_Bool powered;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (e_bluez_adapter_powered_get(element, &powered))
+     printf(":::Adapter powered = \"%hhu\"\n", powered);
+   else
+     fputs("ERROR: can't get adapter powered\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_adapter_set_powered(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args;
+   Eina_Bool powered;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the powered value\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   powered = !!atol(next_args);
+
+   if (e_bluez_adapter_powered_set
+       (element, powered, _method_success_check, "adapter_set_powered"))
+     printf(":::Adapter %s Powered set to %hhu\n", element->path, powered);
+   else
+     fputs("ERROR: can't set device powered\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_adapter_get_discoverable(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args;
+   Eina_Bool discoverable;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (e_bluez_adapter_discoverable_get(element, &discoverable))
+     printf(":::Adapter discoverable = \"%hhu\"\n", discoverable);
+   else
+     fputs("ERROR: can't get adapter discoverable\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_adapter_set_discoverable(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args;
+   Eina_Bool discoverable;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the discoverable value\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   discoverable = !!atol(next_args);
+
+   if (e_bluez_adapter_discoverable_set
+       (element, discoverable, _method_success_check, "adapter_set_discoverable"))
+     printf(":::Adapter %s discoverable set to %hhu\n", element->path, discoverable);
+   else
+     fputs("ERROR: can't set adapter discoverable\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_adapter_get_discoverable_timeout(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args;
+   unsigned int timeout;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (e_bluez_adapter_discoverable_timeout_get(element, &timeout))
+     printf(":::Adapter %s DiscovableTimeout = %hu\n", element->path, timeout);
+   else
+     fputs("ERROR: can't get adapter discoverable timeout\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_adapter_set_discoverable_timeout(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args, *p;
+   unsigned int timeout;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (!next_args) {
+      fprintf(stderr, "ERROR: missing timeout value\n");
+      return ECORE_CALLBACK_RENEW;
+   }
+
+   timeout = strtol(next_args, &p, 0);
+   if (p == next_args)
+     {
+       fprintf(stderr, "ERROR: invalid number \"%s\".\n", next_args);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   if (e_bluez_adapter_discoverable_timeout_set(element, timeout,
+                       _method_success_check,
+                       "adapter_set_discoverable_timeout"))
+     printf(":::Adapter %s scan interval set to %hu\n", element->path, timeout);
+   else
+     fputs("ERROR: can't set adapter discoverable timeout\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_adapter_get_discovering(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args;
+   Eina_Bool discovering;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (e_bluez_adapter_discovering_get(element, &discovering))
+     printf(":::Adapter discovering = \"%hhu\"\n", discovering);
+   else
+     fputs("ERROR: can't get adapter's Discovering\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_adapter_start_discovery(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (e_bluez_adapter_start_discovery(element,
+        _method_success_check, "adapter_start_discovery"))
+     printf(":::Adapter Start Discovery for %s\n", element->path);
+   else
+     fputs("ERROR: can't start discovery on adapter \n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_adapter_stop_discovery(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (e_bluez_adapter_stop_discovery(element,
+        _method_success_check, "adapter_stop_discovery"))
+     printf(":::Adapter Stop Discovery for %s\n", element->path);
+   else
+     fputs("ERROR: can't stop discovery on adapter \n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_adapter_create_paired_device(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args, *path, *cap, *device;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (!next_args) {
+          fputs("ERROR: missing parameters name, type and value.\n", stderr);
+          return ECORE_CALLBACK_RENEW;
+   }
+
+   path = next_args;
+   cap = _tok(path);
+   if (!cap) {
+          fputs("ERROR: missing parameters name, type and value.\n", stderr);
+          return ECORE_CALLBACK_RENEW;
+   }
+   device = _tok(cap);
+   if (!device) {
+          fputs("ERROR: missing parameters name, type and value.\n", stderr);
+          return ECORE_CALLBACK_RENEW;
+   }
+
+   if (e_bluez_adapter_create_paired_device(element, path, cap, device,
+               _create_paired_device_cb, "adapter_create_paired_device")) {
+     printf(":::Creating Paired Device %s (%s)...\n", path, cap);
+     iface = e_dbus_interface_new("org.bluez.Agent");
+     if (!iface) {
+        fputs("WARNING: Cannot add org.bluez.Agent interface",stderr);
+        return EINA_FALSE;
+     }
+     _msgbus_data->obj = e_dbus_object_add(_msgbus_data->conn, path, NULL);
+     e_dbus_object_interface_attach(_msgbus_data->obj, iface);
+     e_dbus_interface_method_add(iface, "RequestPinCode", "o", "s",
+                    _request_pincode_cb);
+
+   }
+   else
+     fprintf(stderr, "ERROR: can't create paired device %s\n", path);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+/* Devices Commands */
+
+static Eina_Bool
+_on_cmd_device_get_name(__UNUSED__ char *cmd, char *args)
+{
+   const char *name;
+   char *next_args;
+   E_Bluez_Element *element = _element_from_args(args, &next_args);
+
+   if (!element)
+          return ECORE_CALLBACK_RENEW;
+
+   if (e_bluez_device_name_get(element, &name))
+     printf(":::Device name = \"%s\"\n", name);
+   else
+     fputs("ERROR: can't get device name\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_input(__UNUSED__ void *data, Ecore_Fd_Handler *fd_handler)
+{
+   char buf[256];
+   char *cmd, *args;
+   const struct {
+      const char *cmd;
+      Eina_Bool (*cb)(char *cmd, char *args);
+   } *itr, maps[] = {
+     {"quit", _on_cmd_quit},
+     {"sync", _on_cmd_sync},
+     {"get_all", _on_cmd_get_all},
+     {"print", _on_cmd_print},
+     {"get_properties", _on_cmd_get_properties},
+     {"set_property", _on_cmd_property_set},
+     {"manager_get", _on_cmd_manager_get},
+     {"manager_default_adapter", _on_cmd_manager_default_adapter},
+     {"adapter_register_agent", _on_cmd_adapter_register_agent},
+     {"adapter_unregister_agent", _on_cmd_adapter_unregister_agent},
+     {"adapter_get_address", _on_cmd_adapter_get_address},
+     {"adapter_get_name", _on_cmd_adapter_get_name},
+     {"adapter_set_name", _on_cmd_adapter_set_name},
+     {"adapter_get_powered", _on_cmd_adapter_get_powered},
+     {"adapter_set_powered", _on_cmd_adapter_set_powered},
+     {"adapter_get_discoverable", _on_cmd_adapter_get_discoverable},
+     {"adapter_set_discoverable", _on_cmd_adapter_set_discoverable},
+     {"adapter_get_discoverable_timeout", _on_cmd_adapter_get_discoverable_timeout},
+     {"adapter_set_discoverable_timeout", _on_cmd_adapter_set_discoverable_timeout},
+     {"adapter_get_discovering", _on_cmd_adapter_get_discovering},
+     {"adapter_start_discovery", _on_cmd_adapter_start_discovery},
+     {"adapter_stop_discovery", _on_cmd_adapter_stop_discovery},
+     {"adapter_create_paired_device", _on_cmd_adapter_create_paired_device},
+     {"device_get_name", _on_cmd_device_get_name},
+     {NULL, NULL}
+   };
+
+
+   if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
+     {
+       fputs("ERROR: reading from stdin, exit\n", stderr);
+       return EINA_FALSE;
+     }
+
+   if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
+     {
+       fputs("ERROR: nothing to read?\n", stderr);
+       return EINA_FALSE;
+     }
+
+   if (!fgets(buf, sizeof(buf), stdin))
+     {
+       fprintf(stderr, "ERROR: could not read command: %s\n", strerror(errno));
+       ecore_main_loop_quit();
+       return EINA_FALSE;
+     }
+
+   cmd = buf;
+   while (isspace(*cmd))
+     cmd++;
+
+   args = strchr(cmd, ' ');
+   if (args)
+     {
+       char *p;
+
+       *args = '\0';
+       args++;
+
+       while (isspace(*args))
+         args++;
+
+       p = args + strlen(args) - 1;
+       if (*p == '\n')
+         *p = '\0';
+     }
+   else
+     {
+       char *p;
+
+       p = cmd + strlen(cmd) - 1;
+       if (*p == '\n')
+         *p = '\0';
+     }
+
+   if (strcmp(cmd, "help") == 0)
+     {
+       if (args)
+         {
+            printf("Commands with '%s' in the name:\n", args);
+            for (itr = maps; itr->cmd; itr++)
+              if (strstr(itr->cmd, args))
+                printf("\t%s\n", itr->cmd);
+         }
+       else
+         {
+            fputs("Commands:\n", stdout);
+            for (itr = maps; itr->cmd; itr++)
+              printf("\t%s\n", itr->cmd);
+         }
+       fputc('\n', stdout);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   for (itr = maps; itr->cmd; itr++)
+     if (strcmp(itr->cmd, cmd) == 0)
+       return itr->cb(cmd, args);
+
+   printf("unknown command \"%s\", args=%s\n", cmd, args);
+   return ECORE_CALLBACK_RENEW;
+}
+
+int
+main(__UNUSED__ int argc,__UNUSED__ char *argv[])
+{
+   ecore_init();
+   e_dbus_init();
+   eina_init();
+
+   _msgbus_data = calloc(1, sizeof(E_Msgbus_Data));
+   _msgbus_data->conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
+   if (!_msgbus_data->conn) {
+      printf("ERROR: can't connect to system session\n");
+      return -1;
+   }
+
+   e_bluez_system_init(_msgbus_data->conn);
+
+   ecore_event_handler_add(E_BLUEZ_EVENT_ELEMENT_ADD, _on_element_add, NULL);
+   ecore_event_handler_add(E_BLUEZ_EVENT_ELEMENT_DEL, _on_element_del, NULL);
+   ecore_event_handler_add(E_BLUEZ_EVENT_ELEMENT_UPDATED,
+                          _on_element_updated, NULL);
+   ecore_event_handler_add(E_BLUEZ_EVENT_DEVICE_FOUND,
+                          _on_device_found, NULL);
+
+   ecore_main_fd_handler_add
+     (0, ECORE_FD_READ | ECORE_FD_ERROR, _on_input, NULL, NULL, NULL);
+
+   ecore_main_loop_begin();
+
+   e_bluez_system_shutdown();
+
+   e_dbus_connection_close(_msgbus_data->conn);
+   eina_shutdown();
+   e_dbus_shutdown();
+   ecore_shutdown();
+
+   fputs("DBG: clean exit.\n", stderr);
+
+   return 0;
+}
diff --git a/src/bin/e_dbus_connman0_7x_test.c b/src/bin/e_dbus_connman0_7x_test.c
new file mode 100644 (file)
index 0000000..e84d4e3
--- /dev/null
@@ -0,0 +1,1726 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#define E_CONNMAN_I_KNOW_THIS_API_IS_SUBJECT_TO_CHANGE 1
+#include "connman0_7x/E_Connman.h"
+
+static void
+_method_success_check(void *data, __UNUSED__ DBusMessage *msg, DBusError *error)
+{
+   const char *name = data;
+
+   if ((!error) || (!dbus_error_is_set(error)))
+     {
+       printf("SUCCESS: method %s() finished successfully.\n", name);
+       return;
+     }
+
+   printf("FAILURE: method %s() finished with error: %s %s\n",
+         name, error->name, error->message);
+   dbus_error_free(error);
+}
+
+static void
+_elements_print(E_Connman_Element **elements, unsigned int count)
+{
+   unsigned int i;
+   for (i = 0; i < count; i++)
+     {
+       printf("--- element %d:\n", i);
+       e_connman_element_print(stdout, elements[i]);
+     }
+   free(elements);
+   printf("END: all elements count = %u\n", count);
+}
+
+static void
+_strings_print(const char **strings, unsigned int count)
+{
+   unsigned int i;
+   for (i = 0; i < count; i++)
+     printf("--- strings %d: \"%s\"\n", i, strings[i]);
+   free(strings);
+   printf("END: all strings count = %u\n", count);
+}
+
+static Eina_Bool
+_on_element_add(__UNUSED__ void *data, __UNUSED__ int type, void *info)
+{
+   E_Connman_Element *element = info;
+   printf(">>> %s\n", element->path);
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_on_element_del(__UNUSED__ void *data, __UNUSED__ int type, void *info)
+{
+   E_Connman_Element *element = info;
+   printf("<<< %s\n", element->path);
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_on_element_updated(__UNUSED__ void *data, __UNUSED__ int type, void *info)
+{
+   E_Connman_Element *element = info;
+   printf("!!! %s\n", element->path);
+   e_connman_element_print(stderr, element);
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_on_cmd_quit(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   fputs("Bye!\n", stderr);
+   ecore_main_loop_quit();
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_on_cmd_sync(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   e_connman_manager_sync_elements();
+   return ECORE_CALLBACK_RENEW;
+}
+
+static char *
+_tok(char *p)
+{
+   p = strchr(p, ' ');
+   if (!p)
+     return NULL;
+
+   *p = '\0';
+   p++;
+   while (isspace(*p))
+     p++;
+   if (*p == '\0')
+     return NULL;
+
+   return p;
+}
+
+static Eina_Bool
+_on_cmd_get_all(__UNUSED__ char *cmd, char *args)
+{
+   E_Connman_Element **elements;
+   char *type;
+   unsigned int count;
+   Eina_Bool ret;
+
+   if (!args)
+     type = NULL;
+   else
+     type = args;
+
+   if (type)
+     ret = e_connman_elements_get_all_type(type, &count, &elements);
+   else
+     ret = e_connman_elements_get_all(&count, &elements);
+
+   if (!ret)
+     fputs("ERROR: could not get elements\n", stderr);
+   else
+     {
+       printf("BEG: all elements type=%s count = %d\n", type, count);
+       _elements_print(elements, count);
+     }
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static E_Connman_Element *
+_element_from_args(char *args, char **next_args)
+{
+   E_Connman_Element *element;
+
+   if (!args)
+     {
+       fputs("ERROR: missing element path\n", stderr);
+       *next_args = NULL;
+       return NULL;
+     }
+
+   *next_args = _tok(args);
+   element = e_connman_element_get(args);
+   if (!element)
+     fprintf(stderr, "ERROR: no element called \"%s\".\n", args);
+
+   return element;
+}
+
+static Eina_Bool
+_on_cmd_print(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args;
+   E_Connman_Element *element = _element_from_args(args, &next_args);
+   if (element)
+     e_connman_element_print(stdout, element);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_get_properties(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args;
+   E_Connman_Element *element = _element_from_args(args, &next_args);
+   if (element)
+     e_connman_element_properties_sync(element);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_property_set(__UNUSED__ char *cmd, char *args)
+{
+   char *next_args, *name, *p;
+   E_Connman_Element *element = _element_from_args(args, &next_args);
+   void *value;
+   long vlong;
+   unsigned short vu16;
+   unsigned int vu32;
+   int type;
+
+   if (!element)
+     return ECORE_CALLBACK_RENEW;
+
+   if (!next_args)
+     {
+       fputs("ERROR: missing parameters name, type and value.\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   name = next_args;
+   p = _tok(name);
+   if (!p)
+     {
+       fputs("ERROR: missing parameters type and value.\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   next_args = _tok(p);
+   if (!next_args)
+     {
+       fputs("ERROR: missing parameter value.\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   type = p[0];
+   switch (type)
+     {
+      case DBUS_TYPE_BOOLEAN:
+        vlong = !!atol(next_args);
+        value = &vlong;
+        fprintf(stderr, "DBG: boolean is: %ld\n", vlong);
+        break;
+      case DBUS_TYPE_UINT16:
+        vu16 = strtol(next_args, &p, 0);
+        if (p == next_args)
+          {
+             fprintf(stderr, "ERROR: invalid number \"%s\".\n", next_args);
+             return ECORE_CALLBACK_RENEW;
+          }
+        value = &vu16;
+        fprintf(stderr, "DBG: u16 is: %hu\n", vu16);
+        break;
+      case DBUS_TYPE_UINT32:
+        vu32 = strtol(next_args, &p, 0);
+        if (p == next_args)
+          {
+             fprintf(stderr, "ERROR: invalid number \"%s\".\n", next_args);
+             return ECORE_CALLBACK_RENEW;
+          }
+        value = &vu32;
+        fprintf(stderr, "DBG: u16 is: %u\n", vu32);
+        break;
+      case DBUS_TYPE_STRING:
+      case DBUS_TYPE_OBJECT_PATH:
+        p = next_args + strlen(next_args);
+        if (p > next_args)
+          p--;
+        while (p > next_args && isspace(*p))
+          p--;
+        if (p <= next_args)
+          {
+             fprintf(stderr, "ERROR: invalid string \"%s\".\n", next_args);
+          }
+        p[1] = '\0';
+        value = next_args;
+        fprintf(stderr, "DBG: string is: \"%s\"\n", next_args);
+        break;
+      default:
+        fprintf(stderr, "ERROR: don't know how to parse type '%c' (%d)\n",
+                type, type);
+        return ECORE_CALLBACK_RENEW;
+     }
+
+   fprintf(stderr, "set_property %s [%p] %s %c %p...\n",
+          args, element, name, type, value);
+   if (!e_connman_element_property_set(element, name, type, value))
+       fputs("ERROR: error setting property.\n", stderr);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+
+/* Manager Commands */
+
+static Eina_Bool
+_on_cmd_manager_get(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   E_Connman_Element *element;
+   element = e_connman_manager_get();
+   e_connman_element_print(stderr, element);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_get_profiles(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   unsigned int count;
+   E_Connman_Element **profiles;
+
+   if (!e_connman_manager_profiles_get(&count, &profiles))
+     {
+       fputs("ERROR: can't get profiles\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   printf("BEG: all manager profiles elements count = %d\n", count);
+   _elements_print(profiles, count);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_get_services(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   unsigned int count;
+   E_Connman_Element **services;
+
+   if (!e_connman_manager_services_get(&count, &services))
+     {
+       fputs("ERROR: can't get services\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   printf("BEG: all manager services elements count = %d\n", count);
+   _elements_print(services, count);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_register_agent(__UNUSED__ char *cmd, char *args)
+{
+   char *path;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the object path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   path = args;
+   if (e_connman_manager_agent_register
+       (path, _method_success_check, "manager_register_agent"))
+     printf(":::Registering agent %s...\n", path);
+   else
+     fprintf(stderr, "ERROR: can't register agent %s\n", path);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_unregister_agent(__UNUSED__ char *cmd, char *args)
+{
+   char *path;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the object path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   path = args;
+   if (e_connman_manager_agent_unregister
+       (path, _method_success_check, "manager_unregister_agent"))
+     printf(":::Unregistering agent %s...\n", path);
+   else
+     fprintf(stderr, "ERROR: can't unregister agent %s\n", path);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_get_state(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   const char *state;
+   if (e_connman_manager_state_get(&state))
+     printf(":::Manager state = \"%s\"\n", state);
+   else
+     fputs("ERROR: can't get manager state\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_get_offline_mode(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   Eina_Bool offline;
+   if (e_connman_manager_offline_mode_get(&offline))
+     printf(":::Manager Offline Mode = %hhu\n", offline);
+   else
+     fputs("ERROR: can't get manager offline mode\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_set_offline_mode(__UNUSED__ char *cmd, char *args)
+{
+   Eina_Bool offline;
+   if (!args)
+     {
+       fputs("ERROR: missing the offline mode value\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   offline = !!atol(args);
+   if (e_connman_manager_offline_mode_set
+       (offline, _method_success_check, "manager_set_offline_mode"))
+
+     printf(":::Manager Offline Mode set to %hhu\n", offline);
+   else
+     fputs("ERROR: can't set manager offline mode\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_request_scan(__UNUSED__ char *cmd, char *args)
+{
+   if (args)
+     _tok(args);
+
+   if (!args)
+     args = "";
+
+   if (e_connman_manager_request_scan
+       (args, _method_success_check, "manager_request_scan"))
+     printf(":::Manager Request Scan for %s\n", args[0] ? args : "<all>");
+   else
+     fputs("ERROR: can't request scan on manager\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_technology_enable(__UNUSED__ char *cmd, char *args)
+{
+   if (!args)
+     {
+       fputs("ERROR: missing the technology type\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+
+   if (e_connman_manager_technology_enable
+       (args, _method_success_check, "manager_technology_enable"))
+     printf(":::Manager Enable Technology %s\n", args);
+   else
+     fputs("ERROR: can't enable technology on manager\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_technology_disable(__UNUSED__ char *cmd, char *args)
+{
+   if (!args)
+     {
+       fputs("ERROR: missing the technology type\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+
+   if (e_connman_manager_technology_disable
+       (args, _method_success_check, "manager_technology_disable"))
+     printf(":::Manager Disable Technology %s\n", args);
+   else
+     fputs("ERROR: can't disable technology on manager\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_get_technologies_available(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   const char **strings;
+   unsigned int count;
+
+   if (!e_connman_manager_technologies_available_get(&count, &strings))
+     fputs("ERROR: can't get available technologies\n", stderr);
+   else
+     {
+       printf("BEG: available technologies count = %u\n", count);
+       _strings_print(strings, count);
+     }
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_get_technologies_enabled(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   const char **strings;
+   unsigned int count;
+
+   if (!e_connman_manager_technologies_enabled_get(&count, &strings))
+     fputs("ERROR: can't get enabled technologies\n", stderr);
+   else
+     {
+       printf("BEG: enabled technologies count = %u\n", count);
+       _strings_print(strings, count);
+     }
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_get_technologies_connected(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   const char **strings;
+   unsigned int count;
+
+   if (!e_connman_manager_technologies_connected_get(&count, &strings))
+     fputs("ERROR: can't get connected technologies\n", stderr);
+   else
+     {
+       printf("BEG: connected technologies count = %u\n", count);
+       _strings_print(strings, count);
+     }
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_profile_remove(__UNUSED__ char *cmd, char *args)
+{
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the profile path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+
+   e = e_connman_profile_get(args);
+   if (e_connman_manager_profile_remove
+       (e, _method_success_check, "manager_profile_remove"))
+     printf(":::Manager Remove Profile %s\n", args);
+   else
+     fputs("ERROR: can't remove profile from manager\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_profile_get_active(__UNUSED__ char *cmd, __UNUSED__ char *args)
+{
+   E_Connman_Element *e;
+
+   if (!e_connman_manager_profile_active_get(&e))
+     fputs("ERROR: can't active_get profile from manager\n", stderr);
+   else
+     e_connman_element_print(stderr, e);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_manager_profile_set_active(__UNUSED__ char *cmd, char *args)
+{
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the profile path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+
+   e = e_connman_profile_get(args);
+   if (e_connman_manager_profile_active_set
+       (e, _method_success_check, "manager_profile_set_active"))
+     printf(":::Manager Active Profile set to %s\n", args);
+   else
+     fputs("ERROR: can't set active profile\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+/* Profile Commands */
+
+static Eina_Bool
+_on_cmd_profile_get_name(__UNUSED__ char *cmd, char *args)
+{
+   const char *name, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the profile path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_profile_get(path);
+   if (e_connman_profile_name_get(e, &name))
+     printf(":::Profile %s Name = \"%s\"\n", path, name);
+   else
+     fputs("ERROR: can't get profile name\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_profile_set_name(__UNUSED__ char *cmd, char *args)
+{
+   char *path, *next_args;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the profile path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   path = args;
+   next_args = _tok(args);
+   if (!next_args)
+     {
+       fputs("ERROR: missing the offline mode value\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(next_args);
+
+   e = e_connman_profile_get(path);
+   if (e_connman_profile_name_set
+       (e, next_args, _method_success_check, "profile_set_name"))
+     printf(":::Profile %s Name set to %s\n", path, next_args);
+   else
+     fputs("ERROR: can't set profile name\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_profile_get_offline_mode(__UNUSED__ char *cmd, char *args)
+{
+   char *path;
+   Eina_Bool offline;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the profile path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_profile_get(path);
+   if (e_connman_profile_offline_mode_get(e, &offline))
+     printf(":::Profile  %s Offline Mode = %hhu\n", path, offline);
+   else
+     fputs("ERROR: can't get profile offline mode\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_profile_set_offline_mode(__UNUSED__ char *cmd, char *args)
+{
+   char *path, *next_args;
+   Eina_Bool offline;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the profile path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   path = args;
+   next_args = _tok(args);
+   if (!next_args)
+     {
+       fputs("ERROR: missing the offline mode value\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(next_args);
+   offline = !!atol(next_args);
+
+   e = e_connman_profile_get(path);
+   if (e_connman_profile_offline_mode_set
+       (e, offline, _method_success_check, "profile_set_offline_mode"))
+     printf(":::Profile %s Offline Mode set to %hhu\n", path, offline);
+   else
+     fputs("ERROR: can't set profile offline mode\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_profile_get_services(__UNUSED__ char *cmd, char *args)
+{
+   E_Connman_Element **services;
+   E_Connman_Element *e;
+   unsigned int count;
+   char *path;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the profile path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_profile_get(path);
+   if (!e_connman_profile_services_get(e, &count, &services))
+     {
+       fputs("ERROR: can't get services\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   printf("BEG: all profile services count = %d\n", count);
+   _elements_print(services, count);
+   return ECORE_CALLBACK_RENEW;
+}
+
+
+/* Services Commands */
+static Eina_Bool
+_on_cmd_service_connect(__UNUSED__ char *cmd, char *args)
+{
+   char *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_connect
+       (e, _method_success_check, "service_connect"))
+     printf(":::Connecting to Service %s...\n", path);
+   else
+     fputs("ERROR: can't connect to service\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_disconnect(__UNUSED__ char *cmd, char *args)
+{
+   char *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_disconnect
+       (e, _method_success_check, "service_disconnect"))
+     printf(":::Disconnecting Service %s...\n", path);
+   else
+     fputs("ERROR: can't disconnect service\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_remove(__UNUSED__ char *cmd, char *args)
+{
+   char *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_remove
+       (e, _method_success_check, "service_remove"))
+     printf(":::Removing Service %s...\n", path);
+   else
+     fputs("ERROR: can't remove service\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_move_before(__UNUSED__ char *cmd, char *args)
+{
+   char *path, *service_path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   service_path = args;
+   path = _tok(args);
+
+   if (!path)
+     {
+       fputs("ERROR: missing the object service\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(path);
+
+   e = e_connman_service_get(service_path);
+   if (e_connman_service_move_before
+       (e, path, _method_success_check, "service_move_before"))
+     printf(":::Moving before %s...\n", path);
+   else
+     fputs("ERROR: can't move before\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_move_after(__UNUSED__ char *cmd, char *args)
+{
+   char *path, *service_path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   service_path = args;
+   path = _tok(args);
+
+   if (!path)
+     {
+       fputs("ERROR: missing the object service\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(path);
+
+   e = e_connman_service_get(service_path);
+   if (e_connman_service_move_after
+       (e, path, _method_success_check, "service_move_after"))
+     printf(":::Moving after %s...\n", path);
+   else
+     fputs("ERROR: can't move after\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_state(__UNUSED__ char *cmd, char *args)
+{
+   const char *state, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_state_get(e, &state))
+     printf(":::Service %s State = \"%s\"\n", path, state);
+   else
+     fputs("ERROR: can't get service state\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_error(__UNUSED__ char *cmd, char *args)
+{
+   const char *error, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_error_get(e, &error))
+     printf(":::Service %s Error = \"%s\"\n", path, error);
+   else
+     fputs("ERROR: can't get service error\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_name(__UNUSED__ char *cmd, char *args)
+{
+   const char *name, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_name_get(e, &name))
+     printf(":::Service %s Name = \"%s\"\n", path, name);
+   else
+     fputs("ERROR: can't get service name\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_type(__UNUSED__ char *cmd, char *args)
+{
+   const char *type, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_type_get(e, &type))
+     printf(":::Service %s Type = \"%s\"\n", path, type);
+   else
+     fputs("ERROR: can't get service type\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_security(__UNUSED__ char *cmd, char *args)
+{
+   unsigned int count;
+   const char **security;
+   const char *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_security_get(e, &count, &security))
+     {
+        unsigned int i;
+        for (i = 0; i < count; i++)
+          printf("\"%s\", ", security[i]);
+        putchar('\n');
+     }
+   else
+     fputs("ERROR: can't get service security\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_passphrase(__UNUSED__ char *cmd, char *args)
+{
+   const char *passphrase, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_passphrase_get(e, &passphrase))
+     printf(":::Service %s Passphrase = \"%s\"\n", path, passphrase);
+   else
+     fputs("ERROR: can't get service passphrase\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_set_passphrase(__UNUSED__ char *cmd, char *args)
+{
+   char *passphrase, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   path = args;
+   passphrase = _tok(args);
+
+   if (!passphrase)
+     {
+       fputs("ERROR: missing the passphrase value\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(passphrase);
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_passphrase_set
+       (e, passphrase, _method_success_check, "service_set_passphrase"))
+     printf(":::Service %s passphrase set to \"%s\"\n", path, passphrase);
+   else
+     fputs("ERROR: can't set service passphrase\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_passphrase_required(__UNUSED__ char *cmd, char *args)
+{
+   const char *path;
+   Eina_Bool passphrase;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_passphrase_required_get(e, &passphrase))
+     printf(":::Service %s Passphrase Required = %hhu\n", path, passphrase);
+   else
+     fputs("ERROR: can't get service passphrase required\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_strength(__UNUSED__ char *cmd, char *args)
+{
+   const char *path;
+   unsigned char strength;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_strength_get(e, &strength))
+     printf(":::Service %s Strength = %#02hhx (%d)\n", path, strength, strength);
+   else
+     fputs("ERROR: can't get service strength\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_favorite(__UNUSED__ char *cmd, char *args)
+{
+   const char *path;
+   Eina_Bool favorite;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_favorite_get(e, &favorite))
+     printf(":::Service %s Favorite = %hhu\n", path, favorite);
+   else
+     fputs("ERROR: can't get service favorite\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_immutable(__UNUSED__ char *cmd, char *args)
+{
+   const char *path;
+   Eina_Bool immutable;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_immutable_get(e, &immutable))
+     printf(":::Service %s Immutable = %hhu\n", path, immutable);
+   else
+     fputs("ERROR: can't get service immutable\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_auto_connect(__UNUSED__ char *cmd, char *args)
+{
+   const char *path;
+   Eina_Bool auto_connect;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_auto_connect_get(e, &auto_connect))
+     printf(":::Service %s Auto Connect = %hhu\n", path, auto_connect);
+   else
+     fputs("ERROR: can't get service auto connect\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_set_auto_connect(__UNUSED__ char *cmd, char *args)
+{
+   char *path, *next_args;
+   Eina_Bool auto_connect;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   path = args;
+   next_args = _tok(args);
+
+   if (!next_args)
+     {
+       fputs("ERROR: missing the auto connect value\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(next_args);
+   auto_connect = !!atol(next_args);
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_auto_connect_set
+       (e, auto_connect, _method_success_check, "service_set_auto_connect"))
+     printf(":::Service %s auto connect set to %d\n", path, auto_connect);
+   else
+     fputs("ERROR: can't set service auto connect\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_roaming(__UNUSED__ char *cmd, char *args)
+{
+   const char *path;
+   Eina_Bool roaming;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_roaming_get(e, &roaming))
+     printf(":::Service %s Roaming = %hhu\n", path, roaming);
+   else
+     fputs("ERROR: can't get service roaming\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_ipv4_method(__UNUSED__ char *cmd, char *args)
+{
+   const char *ipv4_method, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_ipv4_method_get(e, &ipv4_method))
+     printf(":::Service %s IPv4 Method = \"%s\"\n", path, ipv4_method);
+   else
+     fputs("ERROR: can't get service ipv4 method\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_ipv4_address(__UNUSED__ char *cmd, char *args)
+{
+   const char *ipv4_address, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_ipv4_address_get(e, &ipv4_address))
+     printf(":::Service %s IPv4 Address = \"%s\"\n", path, ipv4_address);
+   else
+     fputs("ERROR: can't get service ipv4 address\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_ipv4_gateway(__UNUSED__ char *cmd, char *args)
+{
+   const char *ipv4_gateway, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_ipv4_gateway_get(e, &ipv4_gateway))
+     printf(":::Service %s IPv4 Gateway = \"%s\"\n", path, ipv4_gateway);
+   else
+     fputs("ERROR: can't get service ipv4 gateway\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_ipv4_netmask(__UNUSED__ char *cmd, char *args)
+{
+   const char *ipv4_netmask, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_ipv4_netmask_get(e, &ipv4_netmask))
+     printf(":::Service %s IPv4 Netmask = \"%s\"\n", path, ipv4_netmask);
+   else
+     fputs("ERROR: can't get service ipv4 netmask\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_ipv4_configuration_method(__UNUSED__ char *cmd, char *args)
+{
+   const char *ipv4_method, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_ipv4_configuration_method_get(e, &ipv4_method))
+     printf(":::Service %s IPv4 Configuration Method = \"%s\"\n",
+           path, ipv4_method);
+   else
+     fputs("ERROR: can't get service ipv4_configuration method\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_ipv4_configuration_address(__UNUSED__ char *cmd, char *args)
+{
+   const char *ipv4_address, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_ipv4_configuration_address_get(e, &ipv4_address))
+     printf(":::Service %s IPv4 Configuration Address = \"%s\"\n",
+           path, ipv4_address);
+   else
+     fputs("ERROR: can't get service ipv4_configuration address\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_ipv4_configuration_gateway(__UNUSED__ char *cmd, char *args)
+{
+   const char *ipv4_gateway, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_ipv4_configuration_gateway_get(e, &ipv4_gateway))
+     printf(":::Service %s IPv4 Configuration Gateway = \"%s\"\n",
+           path, ipv4_gateway);
+   else
+     fputs("ERROR: can't get service ipv4_configuration gateway\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_ipv4_configuration_netmask(__UNUSED__ char *cmd, char *args)
+{
+   const char *ipv4_netmask, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_ipv4_configuration_netmask_get(e, &ipv4_netmask))
+     printf(":::Service %s IPv4 Configuration Netmask = \"%s\"\n",
+           path, ipv4_netmask);
+   else
+     fputs("ERROR: can't get service ipv4 configuration netmask\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_ipv4_configure_dhcp(__UNUSED__ char *cmd, char *args)
+{
+   char *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   path = args;
+   _tok(args);
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_ipv4_configure_dhcp
+       (e, _method_success_check, "service_ipv4_configure_dhcp"))
+     printf(":::Service %s IPv4 Configuration set to DHCP\n", path);
+   else
+     fputs("ERROR: can't set service ipv4_configuration dhcp\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_ipv4_configure_manual(__UNUSED__ char *cmd, char *args)
+{
+   char *path, *next_args, *address, *netmask = NULL, *gateway = NULL;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   path = args;
+   next_args = _tok(args);
+   if (!next_args)
+     {
+       fputs("ERROR: missing the service address\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   address = next_args;
+   next_args = _tok(next_args);
+   if (next_args)
+      netmask = next_args;
+
+   next_args = _tok(next_args);
+   if (next_args)
+     {
+       gateway = next_args;
+       _tok(next_args);
+     }
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_ipv4_configure_manual
+       (e, address, netmask, gateway,
+       _method_success_check, "service_ipv4_configure_manual"))
+     printf(":::Service %s IPv4 Configuration set to Manual (%s/%s) gw %s\n",
+           path, address, netmask, gateway);
+   else
+     fputs("ERROR: can't set service ipv4_configuration manual\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_ethernet_method(__UNUSED__ char *cmd, char *args)
+{
+   const char *ethernet_method, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_ethernet_method_get(e, &ethernet_method))
+     printf(":::Service %s Ethernet Method = \"%s\"\n", path, ethernet_method);
+   else
+     fputs("ERROR: can't get service ethernet method\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_ethernet_address(__UNUSED__ char *cmd, char *args)
+{
+   const char *ethernet_address, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_ethernet_address_get(e, &ethernet_address))
+     printf(":::Service %s Ethernet Address = \"%s\"\n",
+           path, ethernet_address);
+   else
+     fputs("ERROR: can't get service ethernet address\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_service_get_ethernet_mtu(__UNUSED__ char *cmd, char *args)
+{
+   const char *path;
+   E_Connman_Element *e;
+   unsigned short ethernet_mtu;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the service path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_service_get(path);
+   if (e_connman_service_ethernet_mtu_get(e, &ethernet_mtu))
+     printf(":::Service %s Ethernet MTU = %hu\n", path, ethernet_mtu);
+   else
+     fputs("ERROR: can't get service ethernet mtu\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_technology_get_state(__UNUSED__ char *cmd, char *args)
+{
+   const char *state, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the technology path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_technology_get(path);
+   if (e_connman_technology_state_get(e, &state))
+     printf(":::Technology %s State = \"%s\"\n", path, state);
+   else
+     fputs("ERROR: can't get technology state\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_technology_get_type(__UNUSED__ char *cmd, char *args)
+{
+   const char *type, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the technology path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_technology_get(path);
+   if (e_connman_technology_type_get(e, &type))
+     printf(":::Technology %s Type = \"%s\"\n", path, type);
+   else
+     fputs("ERROR: can't get technology type\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_cmd_technology_get_name(__UNUSED__ char *cmd, char *args)
+{
+   const char *name, *path;
+   E_Connman_Element *e;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the technology path\n", stderr);
+       return ECORE_CALLBACK_RENEW;
+     }
+   _tok(args);
+   path = args;
+
+   e = e_connman_technology_get(path);
+   if (e_connman_technology_name_get(e, &name))
+     printf(":::Technology %s Name = \"%s\"\n", path, name);
+   else
+     fputs("ERROR: can't get technology name\n", stderr);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_on_input(__UNUSED__ void *data, Ecore_Fd_Handler *fd_handler)
+{
+   char buf[256];
+   char *cmd, *args;
+   const struct {
+      const char *cmd;
+      Eina_Bool (*cb)(char *cmd, char *args);
+   } *itr, maps[] = {
+     {"quit", _on_cmd_quit},
+     {"sync", _on_cmd_sync},
+     {"get_all", _on_cmd_get_all},
+     {"print", _on_cmd_print},
+     {"get_properties", _on_cmd_get_properties},
+     {"set_property", _on_cmd_property_set},
+     {"manager_get", _on_cmd_manager_get},
+     {"manager_get_profiles", _on_cmd_manager_get_profiles},
+     {"manager_get_services", _on_cmd_manager_get_services},
+     {"manager_register_agent", _on_cmd_manager_register_agent},
+     {"manager_unregister_agent", _on_cmd_manager_unregister_agent},
+     {"manager_get_state", _on_cmd_manager_get_state},
+     {"manager_get_offline_mode", _on_cmd_manager_get_offline_mode},
+     {"manager_set_offline_mode", _on_cmd_manager_set_offline_mode},
+     {"manager_request_scan", _on_cmd_manager_request_scan},
+     {"manager_technology_enable", _on_cmd_manager_technology_enable},
+     {"manager_technology_disable", _on_cmd_manager_technology_disable},
+     {"manager_get_technologies_available", _on_cmd_manager_get_technologies_available},
+     {"manager_get_technologies_enabled", _on_cmd_manager_get_technologies_enabled},
+     {"manager_get_technologies_connected", _on_cmd_manager_get_technologies_connected},
+     {"manager_profile_remove", _on_cmd_manager_profile_remove},
+     {"manager_profile_get_active", _on_cmd_manager_profile_get_active},
+     {"manager_profile_set_active", _on_cmd_manager_profile_set_active},
+     {"profile_get_name", _on_cmd_profile_get_name},
+     {"profile_set_name", _on_cmd_profile_set_name},
+     {"profile_get_offline_mode", _on_cmd_profile_get_offline_mode},
+     {"profile_set_offline_mode", _on_cmd_profile_set_offline_mode},
+     {"profile_get_services", _on_cmd_profile_get_services},
+     {"service_connect", _on_cmd_service_connect},
+     {"service_disconnect", _on_cmd_service_disconnect},
+     {"service_remove", _on_cmd_service_remove},
+     {"service_move_before", _on_cmd_service_move_before},
+     {"service_move_after", _on_cmd_service_move_after},
+     {"service_get_state", _on_cmd_service_get_state},
+     {"service_get_error", _on_cmd_service_get_error},
+     {"service_get_name", _on_cmd_service_get_name},
+     {"service_get_type", _on_cmd_service_get_type},
+     {"service_get_security", _on_cmd_service_get_security},
+     {"service_get_passphrase", _on_cmd_service_get_passphrase},
+     {"service_set_passphrase", _on_cmd_service_set_passphrase},
+     {"service_get_passphrase_required", _on_cmd_service_get_passphrase_required},
+     {"service_get_strength", _on_cmd_service_get_strength},
+     {"service_get_favorite", _on_cmd_service_get_favorite},
+     {"service_get_immutable", _on_cmd_service_get_immutable},
+     {"service_get_auto_connect", _on_cmd_service_get_auto_connect},
+     {"service_set_auto_connect", _on_cmd_service_set_auto_connect},
+     {"service_get_roaming", _on_cmd_service_get_roaming},
+     {"service_get_ipv4_method", _on_cmd_service_get_ipv4_method},
+     {"service_get_ipv4_address", _on_cmd_service_get_ipv4_address},
+     {"service_get_ipv4_gateway", _on_cmd_service_get_ipv4_gateway},
+     {"service_get_ipv4_netmask", _on_cmd_service_get_ipv4_netmask},
+     {"service_get_ipv4_configuration_method", _on_cmd_service_get_ipv4_configuration_method},
+     {"service_get_ipv4_configuration_address", _on_cmd_service_get_ipv4_configuration_address},
+     {"service_get_ipv4_configuration_gateway", _on_cmd_service_get_ipv4_configuration_gateway},
+     {"service_get_ipv4_configuration_netmask", _on_cmd_service_get_ipv4_configuration_netmask},
+     {"service_ipv4_configure_dhcp", _on_cmd_service_ipv4_configure_dhcp},
+     {"service_ipv4_configure_manual", _on_cmd_service_ipv4_configure_manual},
+     {"service_get_ethernet_method", _on_cmd_service_get_ethernet_method},
+     {"service_get_ethernet_address", _on_cmd_service_get_ethernet_address},
+     {"service_get_ethernet_mtu", _on_cmd_service_get_ethernet_mtu},
+     {"technology_get_state", _on_cmd_technology_get_state},
+     {"technology_get_type", _on_cmd_technology_get_type},
+     {"technology_get_name", _on_cmd_technology_get_name},
+     {NULL, NULL}
+   };
+
+
+   if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
+     {
+       fputs("ERROR: reading from stdin, exit\n", stderr);
+       return ECORE_CALLBACK_CANCEL;
+     }
+
+   if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
+     {
+       fputs("ERROR: nothing to read?\n", stderr);
+       return ECORE_CALLBACK_CANCEL;
+     }
+
+   if (!fgets(buf, sizeof(buf), stdin))
+     {
+       fprintf(stderr, "ERROR: could not read command: %s\n", strerror(errno));
+       ecore_main_loop_quit();
+       return ECORE_CALLBACK_CANCEL;
+     }
+
+   cmd = buf;
+   while (isspace(*cmd))
+     cmd++;
+
+   args = strchr(cmd, ' ');
+   if (args)
+     {
+       char *p;
+
+       *args = '\0';
+       args++;
+
+       while (isspace(*args))
+         args++;
+
+       p = args + strlen(args) - 1;
+       if (*p == '\n')
+         *p = '\0';
+     }
+   else
+     {
+       char *p;
+
+       p = cmd + strlen(cmd) - 1;
+       if (*p == '\n')
+         *p = '\0';
+     }
+
+   if (strcmp(cmd, "help") == 0)
+     {
+       if (args)
+         {
+            printf("Commands with '%s' in the name:\n", args);
+            for (itr = maps; itr->cmd; itr++)
+              if (strstr(itr->cmd, args))
+                printf("\t%s\n", itr->cmd);
+         }
+       else
+         {
+            fputs("Commands:\n", stdout);
+            for (itr = maps; itr->cmd; itr++)
+              printf("\t%s\n", itr->cmd);
+         }
+       fputc('\n', stdout);
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   for (itr = maps; itr->cmd; itr++)
+     if (strcmp(itr->cmd, cmd) == 0)
+       return itr->cb(cmd, args);
+
+   printf("unknown command \"%s\", args=%s\n", cmd, args);
+   return ECORE_CALLBACK_RENEW;
+}
+
+int
+main(__UNUSED__ int argc, __UNUSED__ char *argv[])
+{
+   E_DBus_Connection *c;
+
+   ecore_init();
+   e_dbus_init();
+   eina_init();
+
+   c = e_dbus_bus_get(DBUS_BUS_SYSTEM);
+   if (!c) {
+      printf("ERROR: can't connect to system session\n");
+      return -1;
+   }
+
+   e_connman_system_init(c);
+   ecore_event_handler_add(E_CONNMAN_EVENT_ELEMENT_ADD, _on_element_add, NULL);
+   ecore_event_handler_add(E_CONNMAN_EVENT_ELEMENT_DEL, _on_element_del, NULL);
+   ecore_event_handler_add(E_CONNMAN_EVENT_ELEMENT_UPDATED,
+                          _on_element_updated, NULL);
+
+   ecore_main_fd_handler_add
+     (0, ECORE_FD_READ | ECORE_FD_ERROR, _on_input, NULL, NULL, NULL);
+
+   ecore_main_loop_begin();
+
+   e_connman_system_shutdown();
+
+   e_dbus_connection_close(c);
+   eina_shutdown();
+   e_dbus_shutdown();
+   ecore_shutdown();
+
+   fputs("DBG: clean exit.\n", stderr);
+
+   return 0;
+}
diff --git a/src/bin/e_dbus_connman0_7x_test_api.c b/src/bin/e_dbus_connman0_7x_test_api.c
new file mode 100644 (file)
index 0000000..c8450e8
--- /dev/null
@@ -0,0 +1,619 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define E_CONNMAN_I_KNOW_THIS_API_IS_SUBJECT_TO_CHANGE 1
+#include "connman0_7x/E_Connman.h"
+#include <stdio.h>
+#include <string.h>
+
+#define DBG(...) EINA_LOG_DBG(__VA_ARGS__)
+#define INF(...) EINA_LOG_INFO(__VA_ARGS__)
+#define WRN(...) EINA_LOG_WARN(__VA_ARGS__)
+#define ERR(...) EINA_LOG_ERR(__VA_ARGS__)
+
+static int success = 0;
+static int failure = 0;
+static Ecore_Timer *exiter = NULL;
+
+static Eina_Bool
+_test_string_get(E_Connman_Element *element, const char *name, Eina_Bool (*func)(const E_Connman_Element *element, const char **value))
+{
+   const char *value;
+   Eina_Bool ret;
+
+   INF("BEGIN: testing string get %s of element %s...", name, element->path);
+   ret = func(element, &value);
+   if (ret)
+     INF("SUCCESS: testing string get %s of element %s: %s",
+        name, element->path, value);
+   else
+     WRN("FAILURE: testing string get %s of element %s",
+        name, element->path);
+
+   return ret;
+}
+
+static Eina_Bool
+_test_string_array_get(E_Connman_Element *element, const char *name, Eina_Bool (*func)(const E_Connman_Element *element, unsigned int *count, const char ***value))
+{
+   const char **value;
+   unsigned int count;
+   Eina_Bool ret;
+
+   INF("BEGIN: testing string array get %s of element %s...",
+       name, element->path);
+   ret = func(element, &count, &value);
+   if (ret)
+     {
+       INF("SUCCESS: testing string array get %s of element %s: %p[%u]",
+           name, element->path, value, count);
+     }
+   else
+     WRN("FAILURE: testing string get %s of element %s",
+        name, element->path);
+
+   return ret;
+}
+
+static Eina_Bool
+_test_bool_get(E_Connman_Element *element, const char *name, Eina_Bool (*func)(const E_Connman_Element *element, Eina_Bool *value))
+{
+   Eina_Bool value, ret;
+
+   INF("BEGIN: testing Eina_Bool get %s of element %s...", name, element->path);
+   ret = func(element, &value);
+   if (ret)
+     INF("SUCCESS: testing Eina_Bool get %s of element %s: %hhu",
+        name, element->path, value);
+   else
+     WRN("FAILURE: testing Eina_Bool get %s of element %s",
+        name, element->path);
+
+   return ret;
+}
+
+static Eina_Bool
+_test_uchar_get(E_Connman_Element *element, const char *name, Eina_Bool (*func)(const E_Connman_Element *element, unsigned char *value))
+{
+   unsigned char value;
+   Eina_Bool ret;
+
+   INF("BEGIN: testing uchar get %s of element %s...", name, element->path);
+   ret = func(element, &value);
+   if (ret)
+     INF("SUCCESS: testing uchar get %s of element %s: %hhu",
+        name, element->path, value);
+   else
+     WRN("FAILURE: testing uchar get %s of element %s",
+        name, element->path);
+
+   return ret;
+}
+
+static Eina_Bool
+_test_ushort_get(E_Connman_Element *element, const char *name, Eina_Bool (*func)(const E_Connman_Element *element, unsigned short *value))
+{
+   unsigned short value;
+   Eina_Bool ret;
+
+   INF("BEGIN: testing ushort get %s of element %s...", name, element->path);
+   ret = func(element, &value);
+   if (ret)
+     INF("SUCCESS: testing ushort get %s of element %s: %hu",
+        name, element->path, value);
+   else
+     WRN("FAILURE: testing ushort get %s of element %s",
+        name, element->path);
+
+   return ret;
+}
+
+static Eina_Bool
+_test_uchar_array_get(E_Connman_Element *element, const char *name, Eina_Bool (*func)(const E_Connman_Element *element, unsigned int *count, unsigned char **value))
+{
+   unsigned char *value;
+   unsigned int count;
+   Eina_Bool ret;
+
+   INF("BEGIN: testing uchar array get %s of element %s...",
+       name, element->path);
+   ret = func(element, &count, &value);
+   if (ret)
+     {
+       INF("SUCCESS: testing uchar array get %s of element %s: %p[%u]",
+           name, element->path, value, count);
+       free(value);
+     }
+   else
+     WRN("FAILURE: testing uchar array get %s of element %s",
+        name, element->path);
+
+   return ret;
+}
+
+static Eina_Bool
+_test_element_get(E_Connman_Element *element, const char *name, Eina_Bool (*func)(const E_Connman_Element *element, E_Connman_Element **value))
+{
+   E_Connman_Element *value;
+   Eina_Bool ret;
+
+   INF("BEGIN: testing element get %s of element %s...", name, element->path);
+   ret = func(element, &value);
+   if (ret)
+     INF("SUCCESS: testing element get %s of element %s: %p",
+        name, element->path, value);
+   else
+     WRN("FAILURE: testing element get %s of element %s",
+        name, element->path);
+
+   return ret;
+}
+
+static Eina_Bool
+_test_elements_get(E_Connman_Element *element, const char *name, Eina_Bool (*func)(const E_Connman_Element *element, unsigned int *count, E_Connman_Element ***elements))
+{
+   E_Connman_Element **value;
+   unsigned int count;
+   Eina_Bool ret;
+
+   INF("BEGIN: testing elements get %s of element %s...",
+       name, element->path);
+   ret = func(element, &count, &value);
+   if (ret)
+     {
+       INF("SUCCESS: testing elements get %s of element %s: %p",
+           name, element->path, value);
+       free(value);
+     }
+   else
+     WRN("FAILURE: testing elements get %s of element %s",
+        name, element->path);
+
+   return ret;
+}
+
+static Eina_Bool
+_test_element_get_global(const char *name, Eina_Bool (*func)(E_Connman_Element **value))
+{
+   E_Connman_Element *value;
+   Eina_Bool ret;
+
+   INF("BEGIN: testing element get %s", name);
+   ret = func(&value);
+   if (ret)
+     INF("SUCCESS: testing element get %s: %p", name, value);
+   else
+     WRN("FAILURE: testing element get %s", name);
+
+   return ret;
+}
+
+static Eina_Bool
+_test_elements_get_global(const char *name, Eina_Bool (*func)(unsigned int *count, E_Connman_Element ***elements))
+{
+   E_Connman_Element **value;
+   unsigned int count;
+   Eina_Bool ret;
+
+   INF("BEGIN: testing elements get %s", name);
+   ret = func(&count, &value);
+   if (ret)
+     {
+       INF("SUCCESS: testing elements get %s: %p", name, value);
+       free(value);
+     }
+   else
+     WRN("FAILURE: testing elements get %s", name);
+
+   return ret;
+}
+
+static Eina_Bool
+_test_string_get_global(const char *name, Eina_Bool (*func)(const char **value))
+{
+   const char *value;
+   Eina_Bool ret;
+
+   INF("BEGIN: testing string get %s...", name);
+   ret = func(&value);
+   if (ret)
+     INF("SUCCESS: testing string get %s: %s", name, value);
+   else
+     WRN("FAILURE: testing string get %s", name);
+
+   return ret;
+}
+
+static Eina_Bool
+_test_bool_get_global(const char *name, Eina_Bool (*func)(Eina_Bool *value))
+{
+   Eina_Bool value, ret;
+
+   INF("BEGIN: testing Eina_Bool get %s...", name);
+   ret = func(&value);
+   if (ret)
+     INF("SUCCESS: testing Eina_Bool get %s: %hhu", name, value);
+   else
+     WRN("FAILURE: testing Eina_Bool get %s", name);
+
+   return ret;
+}
+
+static Eina_Bool
+_test_strings_get_global(const char *name, Eina_Bool (*func)(unsigned int *count, const char ***elements))
+{
+   const char **value;
+   unsigned int count;
+   Eina_Bool ret;
+
+   INF("BEGIN: testing strings get %s", name);
+   ret = func(&count, &value);
+   if (ret)
+     {
+       INF("SUCCESS: testing strings get %s: %p", name, value);
+       free(value);
+     }
+   else
+     WRN("FAILURE: testing strings get %s", name);
+
+   return ret;
+}
+
+
+struct test_desc
+{
+   const char *name;
+   enum {
+     TEST_DESC_TYPE_STRING_GET,
+     TEST_DESC_TYPE_STRING_ARRAY_GET,
+     TEST_DESC_TYPE_BOOL_GET,
+     TEST_DESC_TYPE_UCHAR_GET,
+     TEST_DESC_TYPE_USHORT_GET,
+     TEST_DESC_TYPE_UCHAR_ARRAY_GET,
+     TEST_DESC_TYPE_ELEMENT_GET,
+     TEST_DESC_TYPE_ELEMENTS_GET,
+     TEST_DESC_TYPE_ELEMENT_GET_GLOBAL,
+     TEST_DESC_TYPE_ELEMENTS_GET_GLOBAL,
+     TEST_DESC_TYPE_STRING_GET_GLOBAL,
+     TEST_DESC_TYPE_BOOL_GET_GLOBAL,
+     TEST_DESC_TYPE_STRINGS_GET_GLOBAL,
+     TEST_DESC_TYPE_LAST
+   } type;
+   union {
+      Eina_Bool (*string_get)(const E_Connman_Element *element, const char **value);
+      Eina_Bool (*string_array_get)(const E_Connman_Element *element, unsigned int *count, const char ***value);
+      Eina_Bool (*bool_get)(const E_Connman_Element *element, Eina_Bool *value);
+      Eina_Bool (*uchar_get)(const E_Connman_Element *element, unsigned char *value);
+      Eina_Bool (*ushort_get)(const E_Connman_Element *element, unsigned short*value);
+      Eina_Bool (*uchar_array_get)(const E_Connman_Element *element, unsigned int *count, unsigned char **value);
+      Eina_Bool (*element_get)(const E_Connman_Element *element, E_Connman_Element **value);
+      Eina_Bool (*elements_get)(const E_Connman_Element *element, unsigned int *count, E_Connman_Element ***elements);
+      Eina_Bool (*element_get_global)(E_Connman_Element **element);
+      Eina_Bool (*elements_get_global)(unsigned int *count, E_Connman_Element ***elements);
+      Eina_Bool (*string_get_global)(const char **value);
+      Eina_Bool (*bool_get_global)(Eina_Bool *value);
+      Eina_Bool (*strings_get_global)(unsigned int *count, const char ***strings);
+      void *dummy;
+   } func;
+   Eina_Bool may_fail;
+};
+
+#define TEST_DESC_STRING_GET(_func, may_fail)                          \
+  {#_func, TEST_DESC_TYPE_STRING_GET, .func.string_get=_func, may_fail}
+#define TEST_DESC_STRING_ARRAY_GET(_func, may_fail)                            \
+  {#_func, TEST_DESC_TYPE_STRING_ARRAY_GET, .func.string_array_get=_func, may_fail}
+#define TEST_DESC_BOOL_GET(_func, may_fail)                            \
+  {#_func, TEST_DESC_TYPE_BOOL_GET, .func.bool_get=_func, may_fail}
+#define TEST_DESC_UCHAR_GET(_func, may_fail)                           \
+  {#_func, TEST_DESC_TYPE_UCHAR_GET, .func.uchar_get=_func, may_fail}
+#define TEST_DESC_USHORT_GET(_func, may_fail)                          \
+  {#_func, TEST_DESC_TYPE_USHORT_GET, .func.ushort_get=_func, may_fail}
+#define TEST_DESC_UCHAR_ARRAY_GET(_func, may_fail)                     \
+  {#_func, TEST_DESC_TYPE_UCHAR_ARRAY_GET, .func.uchar_array_get=_func, may_fail}
+#define TEST_DESC_ELEMENT_GET(_func, may_fail)                         \
+  {#_func, TEST_DESC_TYPE_ELEMENT_GET, .func.element_get=_func, may_fail}
+#define TEST_DESC_ELEMENTS_GET(_func, may_fail)                                \
+  {#_func, TEST_DESC_TYPE_ELEMENTS_GET, .func.elements_get=_func, may_fail}
+#define TEST_DESC_ELEMENT_GET_GLOBAL(_func, may_fail)                  \
+  {#_func, TEST_DESC_TYPE_ELEMENT_GET_GLOBAL, .func.element_get_global=_func, may_fail}
+#define TEST_DESC_ELEMENTS_GET_GLOBAL(_func, may_fail)                 \
+  {#_func, TEST_DESC_TYPE_ELEMENTS_GET_GLOBAL, .func.elements_get_global=_func, may_fail}
+#define TEST_DESC_STRING_GET_GLOBAL(_func, may_fail)                   \
+  {#_func, TEST_DESC_TYPE_STRING_GET_GLOBAL, .func.string_get_global=_func, may_fail}
+#define TEST_DESC_BOOL_GET_GLOBAL(_func, may_fail)                     \
+  {#_func, TEST_DESC_TYPE_BOOL_GET_GLOBAL, .func.bool_get_global=_func, may_fail}
+#define TEST_DESC_STRINGS_GET_GLOBAL(_func, may_fail)                  \
+  {#_func, TEST_DESC_TYPE_STRINGS_GET_GLOBAL, .func.strings_get_global=_func, may_fail}
+#define TEST_DESC_SENTINEL {NULL, TEST_DESC_TYPE_LAST, .func.dummy=NULL}
+
+static Eina_Bool
+_test_element(E_Connman_Element *element, const struct test_desc *test_descs)
+{
+   const struct test_desc *itr;
+   int total, ok = 0, fail = 0;
+   Eina_Bool ret = EINA_TRUE;
+
+   for (itr = test_descs; itr->type != TEST_DESC_TYPE_LAST; itr++)
+     {
+       Eina_Bool r;
+
+       switch (itr->type)
+         {
+          case TEST_DESC_TYPE_STRING_GET:
+             r = _test_string_get(element, itr->name, itr->func.string_get);
+             break;
+          case TEST_DESC_TYPE_STRING_ARRAY_GET:
+             r = _test_string_array_get
+               (element, itr->name, itr->func.string_array_get);
+             break;
+          case TEST_DESC_TYPE_BOOL_GET:
+             r = _test_bool_get(element, itr->name, itr->func.bool_get);
+             break;
+          case TEST_DESC_TYPE_UCHAR_GET:
+             r = _test_uchar_get(element, itr->name, itr->func.uchar_get);
+             break;
+          case TEST_DESC_TYPE_USHORT_GET:
+             r = _test_ushort_get(element, itr->name, itr->func.ushort_get);
+             break;
+          case TEST_DESC_TYPE_UCHAR_ARRAY_GET:
+             r = _test_uchar_array_get
+               (element, itr->name, itr->func.uchar_array_get);
+             break;
+          case TEST_DESC_TYPE_ELEMENT_GET:
+             r = _test_element_get
+               (element, itr->name, itr->func.element_get);
+             break;
+          case TEST_DESC_TYPE_ELEMENTS_GET:
+             r = _test_elements_get
+               (element, itr->name, itr->func.elements_get);
+             break;
+          case TEST_DESC_TYPE_ELEMENT_GET_GLOBAL:
+             r = _test_element_get_global
+               (itr->name, itr->func.element_get_global);
+             break;
+          case TEST_DESC_TYPE_ELEMENTS_GET_GLOBAL:
+             r = _test_elements_get_global
+               (itr->name, itr->func.elements_get_global);
+             break;
+          case TEST_DESC_TYPE_STRING_GET_GLOBAL:
+             r = _test_string_get_global
+               (itr->name, itr->func.string_get_global);
+             break;
+          case TEST_DESC_TYPE_BOOL_GET_GLOBAL:
+             r = _test_bool_get_global
+               (itr->name, itr->func.bool_get_global);
+             break;
+          case TEST_DESC_TYPE_STRINGS_GET_GLOBAL:
+             r = _test_strings_get_global
+               (itr->name, itr->func.strings_get_global);
+             break;
+          default:
+             ERR("unknown test type %d (%s)", itr->type, itr->name);
+             r = 0;
+             break;
+         }
+
+       if (r || itr->may_fail)
+         ok++;
+       else
+         {
+            ERR("test failed %s, element %s [%s]",
+                itr->name, element->path, element->interface);
+            fail++;
+            ret = EINA_FALSE;
+         }
+     }
+
+   total = ok + failure;
+   success += ok;
+   failure += fail;
+   if (total == 0)
+     {
+       INF("no tests for %s [%s]", element->path, element->interface);
+       return EINA_TRUE;
+     }
+
+   INF("testing %s success: %d, failure: %d: %d%% [%s]",
+       element->path, ok, fail, (ok * 100) / total,
+       element->interface);
+
+   return ret;
+}
+
+static const struct test_desc test_desc_manager[] = {
+  TEST_DESC_STRING_GET_GLOBAL(e_connman_manager_state_get, 0),
+  TEST_DESC_BOOL_GET_GLOBAL(e_connman_manager_offline_mode_get, 0),
+  //TEST_DESC_STRING_SET_GLOBAL(e_connman_manager_request_scan, 0),
+  //TEST_DESC_BOOL_SET_GLOBAL(e_connman_manager_offline_mode_set, 0),
+  TEST_DESC_ELEMENTS_GET_GLOBAL(e_connman_manager_profiles_get, 0),
+  TEST_DESC_ELEMENTS_GET_GLOBAL(e_connman_manager_services_get, 1),
+  TEST_DESC_STRING_GET_GLOBAL(e_connman_manager_technology_default_get, 0),
+  TEST_DESC_STRINGS_GET_GLOBAL(e_connman_manager_technologies_available_get, 0),
+  TEST_DESC_STRINGS_GET_GLOBAL(e_connman_manager_technologies_enabled_get, 0),
+  TEST_DESC_STRINGS_GET_GLOBAL(e_connman_manager_technologies_connected_get, 0),
+  TEST_DESC_ELEMENT_GET_GLOBAL(e_connman_manager_profile_active_get, 0),
+  TEST_DESC_SENTINEL
+};
+
+static const struct test_desc test_desc_profile[] = {
+  TEST_DESC_STRING_GET(e_connman_profile_name_get, 1),
+  //TEST_DESC_STRING_SET(e_connman_profile_name_set, 1),
+  TEST_DESC_BOOL_GET(e_connman_profile_offline_mode_get, 0),
+  //TEST_DESC_BOOL_SET(e_connman_profile_offline_mode_set, 0),
+  TEST_DESC_ELEMENTS_GET(e_connman_profile_services_get, 1),
+  TEST_DESC_SENTINEL
+};
+
+static const struct test_desc test_desc_service[] = {
+  /* TODO: need to check exactly what properties may fail */
+  TEST_DESC_STRING_GET(e_connman_service_state_get, 1),
+  TEST_DESC_STRING_GET(e_connman_service_error_get, 1),
+  TEST_DESC_STRING_GET(e_connman_service_name_get, 0),
+  TEST_DESC_STRING_GET(e_connman_service_type_get, 0),
+  TEST_DESC_STRING_ARRAY_GET(e_connman_service_security_get, 1),
+  TEST_DESC_STRING_GET(e_connman_service_passphrase_get, 1),
+  //TEST_DESC_STRING_SET(e_connman_service_passphrase_set, 1),
+  TEST_DESC_BOOL_GET(e_connman_service_passphrase_required_get, 1),
+  TEST_DESC_UCHAR_GET(e_connman_service_strength_get, 1),
+  TEST_DESC_BOOL_GET(e_connman_service_favorite_get, 0),
+  TEST_DESC_BOOL_GET(e_connman_service_immutable_get, 0),
+  TEST_DESC_BOOL_GET(e_connman_service_auto_connect_get, 0),
+  //TEST_DESC_BOOL_SET(e_connman_service_auto_connect_set, 1),
+  TEST_DESC_BOOL_GET(e_connman_service_roaming_get, 1),
+  TEST_DESC_STRING_GET(e_connman_service_ipv4_method_get, 1),
+  TEST_DESC_STRING_GET(e_connman_service_ipv4_address_get, 1),
+  TEST_DESC_STRING_GET(e_connman_service_ipv4_gateway_get, 1),
+  TEST_DESC_STRING_GET(e_connman_service_ipv4_netmask_get, 1),
+  TEST_DESC_STRING_GET(e_connman_service_ipv4_configuration_method_get, 1),
+  TEST_DESC_STRING_GET(e_connman_service_ipv4_configuration_address_get, 1),
+  TEST_DESC_STRING_GET(e_connman_service_ipv4_configuration_gateway_get, 1),
+  TEST_DESC_STRING_GET(e_connman_service_ipv4_configuration_netmask_get, 1),
+  TEST_DESC_STRING_GET(e_connman_service_ethernet_method_get, 1),
+  TEST_DESC_STRING_GET(e_connman_service_ethernet_address_get, 1),
+  TEST_DESC_USHORT_GET(e_connman_service_ethernet_mtu_get, 1),
+  TEST_DESC_SENTINEL
+};
+
+static Eina_Bool
+_quit(__UNUSED__ void *data)
+{
+   ecore_main_loop_quit();
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_on_exiter(__UNUSED__ void *data)
+{
+   e_connman_system_shutdown();
+   ecore_idle_enterer_add(_quit, NULL);
+   exiter = NULL;
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_exiter_reschedule(void)
+{
+   if (exiter)
+     ecore_timer_del(exiter);
+   exiter = ecore_timer_add(10, _on_exiter, NULL);
+}
+
+struct test_element_timer_data
+{
+   E_Connman_Element *element;
+   Ecore_Timer *timer;
+};
+
+static Eina_Bool
+_test_element_timer(void *data)
+{
+   struct test_element_timer_data *d = data;
+   E_Connman_Element *element = d->element;
+
+   if (e_connman_element_is_profile(element))
+     _test_element(element, test_desc_profile);
+   else if (e_connman_element_is_manager(element))
+     _test_element(element, test_desc_manager);
+   else if (e_connman_element_is_service(element))
+     _test_element(element, test_desc_service);
+   else
+     ERR("!!! don't know how to test %s [%s]",
+        element->path, element->interface);
+
+   _exiter_reschedule();
+
+   d->timer = NULL;
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_element_listener(void *data, __UNUSED__ const E_Connman_Element *element)
+{
+   struct test_element_timer_data *d = data;
+   if (d->timer)
+     ecore_timer_del(d->timer);
+   d->timer = ecore_timer_add(1.0, _test_element_timer, d);
+   _exiter_reschedule();
+}
+
+static void
+_element_listener_free(void *data)
+{
+   struct test_element_timer_data *d = data;
+   if (d->timer)
+     ecore_timer_del(d->timer);
+   free(d);
+}
+
+static Eina_Bool
+_on_element_add(__UNUSED__ void *data, __UNUSED__ int type, void *info)
+{
+   E_Connman_Element *element = info;
+   struct test_element_timer_data *d;
+
+   d = malloc(sizeof(*d));
+   if (!d)
+     return ECORE_CALLBACK_PASS_ON;
+
+   d->element = element;
+   d->timer = ecore_timer_add(1.0, _test_element_timer, d);
+   e_connman_element_listener_add
+     (element, _element_listener, d, _element_listener_free);
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_on_element_del(__UNUSED__ void *data, __UNUSED__ int type, __UNUSED__ void *info)
+{
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_on_element_updated(__UNUSED__ void *data, __UNUSED__ int type, __UNUSED__ void *info)
+{
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+int
+main(__UNUSED__ int argc, __UNUSED__ char *argv[])
+{
+   E_DBus_Connection *c;
+   int total;
+
+   ecore_init();
+   e_dbus_init();
+   eina_init();
+
+   c = e_dbus_bus_get(DBUS_BUS_SYSTEM);
+   if (!c) {
+      printf("ERROR: can't connect to system session\n");
+      return -1;
+   }
+
+   e_connman_system_init(c);
+   ecore_event_handler_add(E_CONNMAN_EVENT_ELEMENT_ADD, _on_element_add, NULL);
+   ecore_event_handler_add(E_CONNMAN_EVENT_ELEMENT_DEL, _on_element_del, NULL);
+   ecore_event_handler_add(E_CONNMAN_EVENT_ELEMENT_UPDATED,
+                          _on_element_updated, NULL);
+
+   _exiter_reschedule();
+
+   ecore_main_loop_begin();
+
+   e_dbus_connection_close(c);
+   eina_stringshare_dump();
+   eina_shutdown();
+   e_dbus_shutdown();
+   ecore_shutdown();
+
+   total = success + failure;
+   if (total == 0)
+     fputs("DBG: clean exit, no tests executed.\n", stderr);
+   else
+     fprintf(stderr, "DBG: clean exit, success: %d, failure: %d, %d%%\n",
+            success, failure, (success * 100) / total);
+
+   return 0;
+}
diff --git a/src/bin/e_dbus_ofono_test.c b/src/bin/e_dbus_ofono_test.c
new file mode 100644 (file)
index 0000000..f6e22af
--- /dev/null
@@ -0,0 +1,520 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "E_Ofono.h"
+
+static void
+_method_success_check(void *data, DBusMessage *msg __UNUSED__, DBusError *error)
+{
+   const char *name = data;
+
+   if ((!error) || (!dbus_error_is_set(error)))
+     {
+       printf("SUCCESS: method %s() finished successfully.\n", name);
+       return;
+     }
+
+   printf("FAILURE: method %s() finished with error: %s %s\n",
+         name, error->name, error->message);
+   dbus_error_free(error);
+}
+
+static void
+_elements_print(E_Ofono_Element **elements, unsigned int count)
+{
+   unsigned int i;
+   for (i = 0; i < count; i++)
+     {
+       printf("--- element %d:\n", i);
+       e_ofono_element_print(stdout, elements[i]);
+     }
+   free(elements);
+   printf("END: all elements count = %u\n", count);
+}
+
+static Eina_Bool
+_on_element_add(void *data __UNUSED__, int type __UNUSED__, void *info)
+{
+   E_Ofono_Element *element = info;
+   printf(">>> %s %s\n", element->path, element->interface);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_on_element_del(void *data __UNUSED__, int type __UNUSED__, void *info)
+{
+   E_Ofono_Element *element = info;
+   printf("<<< %s %s\n", element->path, element->interface);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_on_element_updated(void *data __UNUSED__, int type __UNUSED__, void *info)
+{
+   E_Ofono_Element *element = info;
+   printf("!!! %s %s\n", element->path, element->interface);
+   e_ofono_element_print(stderr, element);
+   return EINA_TRUE;
+}
+static Eina_Bool
+_on_cmd_quit(char *cmd __UNUSED__, char *args __UNUSED__)
+{
+   fputs("Bye!\n", stderr);
+   ecore_main_loop_quit();
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_on_cmd_sync(char *cmd __UNUSED__, char *args __UNUSED__)
+{
+   e_ofono_manager_sync_elements();
+   return EINA_TRUE;
+}
+
+static char *
+_tok(char *p)
+{
+   p = strchr(p, ' ');
+   if (!p)
+     return NULL;
+
+   *p = '\0';
+   p++;
+   while (isspace(*p))
+     p++;
+   if (*p == '\0')
+     return NULL;
+
+   return p;
+}
+
+static Eina_Bool
+_on_cmd_get_all(char *cmd __UNUSED__, char *args)
+{
+   E_Ofono_Element **elements;
+   char *type;
+   unsigned int count;
+   Eina_Bool ret;
+
+   if (!args)
+     type = NULL;
+   else
+     type = args;
+
+   if (type)
+     ret = e_ofono_elements_get_all_type(type, &count, &elements);
+   else
+     ret = e_ofono_elements_get_all(&count, &elements);
+
+   if (!ret)
+     fputs("ERROR: could not get elements\n", stderr);
+   else
+     {
+       printf("BEG: all elements type=%s count = %d\n", type, count);
+       _elements_print(elements, count);
+     }
+
+   return EINA_TRUE;
+}
+
+static E_Ofono_Element *
+_element_from_args(char *interface, char *args, char **next_args)
+{
+   E_Ofono_Element *element;
+
+   if (!args)
+     {
+       fputs("ERROR: missing element path\n", stderr);
+       *next_args = NULL;
+       return NULL;
+     }
+
+   if (!interface)
+     {
+       interface = _tok(args);
+       *next_args = _tok(interface);
+     }
+   else
+     *next_args = _tok(args);
+
+   element = e_ofono_element_get(args, interface);
+   if (!element)
+     fprintf(stderr, "ERROR: no element called \"%s %s\".\n", args, interface);
+
+   return element;
+}
+
+static Eina_Bool
+_on_cmd_print(char *cmd __UNUSED__, char *args)
+{
+   char *next_args;
+   E_Ofono_Element *element = _element_from_args(NULL, args, &next_args);
+   if (element)
+     e_ofono_element_print(stdout, element);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_on_cmd_get_properties(char *cmd __UNUSED__, char *args)
+{
+   char *next_args;
+   E_Ofono_Element *element = _element_from_args(NULL, args, &next_args);
+   if (element)
+     e_ofono_element_properties_sync(element);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_on_cmd_property_set(char *cmd __UNUSED__, char *args)
+{
+   char *next_args, *name, *p;
+   E_Ofono_Element *element = _element_from_args(NULL, args, &next_args);
+   void *value;
+   long vlong;
+   unsigned short vu16;
+   unsigned int vu32;
+   int type;
+
+   if (!element)
+     return EINA_TRUE;
+
+   if (!next_args)
+     {
+       fputs("ERROR: missing parameters name, type and value.\n", stderr);
+       return EINA_TRUE;
+     }
+
+   name = next_args;
+   p = _tok(name);
+   if (!p)
+     {
+       fputs("ERROR: missing parameters type and value.\n", stderr);
+       return EINA_TRUE;
+     }
+
+   next_args = _tok(p);
+   if (!next_args)
+     {
+       fputs("ERROR: missing parameter value.\n", stderr);
+       return EINA_TRUE;
+     }
+
+   type = p[0];
+   switch (type)
+     {
+      case DBUS_TYPE_BOOLEAN:
+        vlong = !!atol(next_args);
+        value = &vlong;
+        fprintf(stderr, "DBG: boolean is: %ld\n", vlong);
+        break;
+      case DBUS_TYPE_UINT16:
+        vu16 = strtol(next_args, &p, 0);
+        if (p == next_args)
+          {
+             fprintf(stderr, "ERROR: invalid number \"%s\".\n", next_args);
+             return EINA_TRUE;
+          }
+        value = &vu16;
+        fprintf(stderr, "DBG: u16 is: %hu\n", vu16);
+        break;
+      case DBUS_TYPE_UINT32:
+        vu32 = strtol(next_args, &p, 0);
+        if (p == next_args)
+          {
+             fprintf(stderr, "ERROR: invalid number \"%s\".\n", next_args);
+             return EINA_TRUE;
+          }
+        value = &vu32;
+        fprintf(stderr, "DBG: u16 is: %u\n", vu32);
+        break;
+      case DBUS_TYPE_STRING:
+      case DBUS_TYPE_OBJECT_PATH:
+        p = next_args + strlen(next_args);
+        if (p > next_args)
+          p--;
+        while (p > next_args && isspace(*p))
+          p--;
+        if (p <= next_args)
+          {
+             fprintf(stderr, "ERROR: invalid string \"%s\".\n", next_args);
+          }
+        p[1] = '\0';
+        value = next_args;
+        fprintf(stderr, "DBG: string is: \"%s\"\n", next_args);
+        break;
+      default:
+        fprintf(stderr, "ERROR: don't know how to parse type '%c' (%d)\n",
+                type, type);
+        return EINA_TRUE;
+     }
+
+   fprintf(stderr, "set_property %s [%p] %s %c %p...\n",
+          args, element, name, type, value);
+   if (!e_ofono_element_property_set(element, name, type, value))
+       fputs("ERROR: error setting property.\n", stderr);
+
+   return EINA_TRUE;
+}
+
+/* Manager Commands */
+
+static Eina_Bool
+_on_cmd_manager_get(char *cmd __UNUSED__, char *args __UNUSED__)
+{
+   E_Ofono_Element *element;
+   element = e_ofono_manager_get();
+   e_ofono_element_print(stderr, element);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_on_cmd_manager_modems_get(char *cmd __UNUSED__, char *args __UNUSED__)
+{
+   char *path;
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+   Eina_Array *modems = NULL;
+
+   if(e_ofono_manager_modems_get(&modems))
+     {
+       printf("[");
+       if (modems)
+         EINA_ARRAY_ITER_NEXT(modems, i, path, iterator)
+            printf(" %s", path);
+       printf(" ]\n");
+     }
+
+   return EINA_TRUE;
+}
+
+/* Modem Commands */
+
+static Eina_Bool
+_on_cmd_modem_set_powered(char *cmd __UNUSED__, char *args)
+{
+   char *next_args;
+   Eina_Bool powered;
+   E_Ofono_Element *element = _element_from_args("org.ofono.Modem", args, &next_args);
+
+   if (!element)
+          return EINA_TRUE;
+
+   if (!args)
+     {
+       fputs("ERROR: missing the powered value\n", stderr);
+       return EINA_TRUE;
+     }
+
+   powered = !!atol(next_args);
+
+   if (e_ofono_modem_powered_set
+       (element, powered, _method_success_check, "modem_set_powered"))
+     printf(":::Modem %s Powered set to %hhu\n", element->path, powered);
+   else
+     fputs("ERROR: can't set Modem Powered\n", stderr);
+   return EINA_TRUE;
+}
+
+/* SMS Commands */
+
+static Eina_Bool
+_on_cmd_sms_sca_set(char *cmd __UNUSED__, char *args)
+{
+   char *next_args, *sca;
+   E_Ofono_Element *element = _element_from_args("org.ofono.SmsManager", args,
+                                                &next_args);
+
+   if (!element)
+     return EINA_TRUE;
+
+   if (!args)
+     {
+       fputs("ERROR: missing service center address\n", stderr);
+       return EINA_TRUE;
+     }
+
+   sca = next_args;
+   if (e_ofono_sms_sca_set(element, sca, _method_success_check,
+                          "sms_sca_set"))
+     printf(":::Service Center Address on modem %s set to %s\n",
+           element->path, sca);
+   else
+     fputs("ERROR: couldn't change Service Center Address\n", stderr);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_on_cmd_sms_send_message(char *cmd __UNUSED__, char *args)
+{
+   char *next_args, *number, *message;
+   E_Ofono_Element *element = _element_from_args("org.ofono.SmsManager", args,
+                                                &next_args);
+
+   if (!element)
+     return EINA_TRUE;
+
+   number = next_args;
+   if (!number)
+     {
+       fputs("ERROR: missing recipient number and message text.\n", stderr);
+       return EINA_TRUE;
+     }
+
+   message = _tok(number);
+   if (!message)
+     {
+       fputs("ERROR: missing message text.\n", stderr);
+       return EINA_TRUE;
+     }
+
+   if (!e_ofono_sms_send_message(element, number, message,
+                                _method_success_check, "sms_send_message"))
+       fputs("ERROR: error setting property.\n", stderr);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_on_input(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler)
+{
+   char buf[256];
+   char *cmd, *args;
+   const struct {
+      const char *cmd;
+      Eina_Bool (*cb)(char *cmd, char *args);
+   } *itr, maps[] = {
+     {"quit", _on_cmd_quit},
+     {"sync", _on_cmd_sync},
+     {"get_all", _on_cmd_get_all},
+     {"print", _on_cmd_print},
+     {"get_properties", _on_cmd_get_properties},
+     {"set_property", _on_cmd_property_set},
+     {"manager_get", _on_cmd_manager_get},
+     {"manager_modems_get", _on_cmd_manager_modems_get},
+     {"modem_set_powered", _on_cmd_modem_set_powered},
+     {"sms_sca_set", _on_cmd_sms_sca_set},
+     {"sms_send_message", _on_cmd_sms_send_message},
+     {NULL, NULL}
+   };
+
+
+   if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
+     {
+       fputs("ERROR: reading from stdin, exit\n", stderr);
+       return EINA_FALSE;
+     }
+
+   if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
+     {
+       fputs("ERROR: nothing to read?\n", stderr);
+       return EINA_FALSE;
+     }
+
+   if (!fgets(buf, sizeof(buf), stdin))
+     {
+       fprintf(stderr, "ERROR: could not read command: %s\n", strerror(errno));
+       ecore_main_loop_quit();
+       return EINA_FALSE;
+     }
+
+   cmd = buf;
+   while (isspace(*cmd))
+     cmd++;
+
+   args = strchr(cmd, ' ');
+   if (args)
+     {
+       char *p;
+
+       *args = '\0';
+       args++;
+
+       while (isspace(*args))
+         args++;
+
+       p = args + strlen(args) - 1;
+       if (*p == '\n')
+         *p = '\0';
+     }
+   else
+     {
+       char *p;
+
+       p = cmd + strlen(cmd) - 1;
+       if (*p == '\n')
+         *p = '\0';
+     }
+
+   if (strcmp(cmd, "help") == 0)
+     {
+       if (args)
+         {
+            printf("Commands with '%s' in the name:\n", args);
+            for (itr = maps; itr->cmd; itr++)
+              if (strstr(itr->cmd, args))
+                printf("\t%s\n", itr->cmd);
+         }
+       else
+         {
+            fputs("Commands:\n", stdout);
+            for (itr = maps; itr->cmd; itr++)
+              printf("\t%s\n", itr->cmd);
+         }
+       fputc('\n', stdout);
+       return EINA_TRUE;
+     }
+
+   for (itr = maps; itr->cmd; itr++)
+     if (strcmp(itr->cmd, cmd) == 0)
+       return itr->cb(cmd, args);
+
+   printf("unknown command \"%s\", args=%s\n", cmd, args);
+   return EINA_TRUE;
+}
+
+int
+main(int argc __UNUSED__, char *argv[] __UNUSED__)
+{
+   E_DBus_Connection *c;
+
+   ecore_init();
+   e_dbus_init();
+   eina_init();
+
+   c = e_dbus_bus_get(DBUS_BUS_SYSTEM);
+   if (!c) {
+      printf("ERROR: can't connect to system session\n");
+      return -1;
+   }
+
+   e_ofono_system_init(c);
+
+   ecore_event_handler_add(E_OFONO_EVENT_ELEMENT_ADD, _on_element_add, NULL);
+   ecore_event_handler_add(E_OFONO_EVENT_ELEMENT_DEL, _on_element_del, NULL);
+   ecore_event_handler_add(E_OFONO_EVENT_ELEMENT_UPDATED,
+                          _on_element_updated, NULL);
+
+   ecore_main_fd_handler_add
+     (0, ECORE_FD_READ | ECORE_FD_ERROR, _on_input, NULL, NULL, NULL);
+
+   ecore_main_loop_begin();
+
+   e_ofono_system_shutdown();
+
+   e_dbus_connection_close(c);
+   eina_shutdown();
+   e_dbus_shutdown();
+   ecore_shutdown();
+
+   fputs("DBG: clean exit.\n", stderr);
+
+   return 0;
+}
diff --git a/src/bin/e_dbus_ukit_test.c b/src/bin/e_dbus_ukit_test.c
new file mode 100644 (file)
index 0000000..1755444
--- /dev/null
@@ -0,0 +1,154 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <Ecore.h>
+
+#include <E_Ukit.h>
+#include <E_DBus.h>
+
+static E_DBus_Connection *econ = NULL;
+
+Eina_Bool
+print_prop(const Eina_Hash *hash, const void *key, void *data, __UNUSED__ void *fdata)
+{
+   const Eina_List *strlist, *l;
+   char *y;
+   E_Ukit_Property *p = data;
+   E_Ukit_Properties props;
+   int err = 0;
+
+   props.properties = (Eina_Hash*)hash;
+   switch (p->type)
+     {
+        case E_UKIT_PROPERTY_TYPE_STRING:
+          printf("\t%s = [%s]\n", (char*)key, e_ukit_property_string_get(&props, key, &err));
+          break;
+        case E_UKIT_PROPERTY_TYPE_INT:
+          printf("\t%s = [%d]\n", (char*)key, e_ukit_property_int_get(&props, key, &err));
+          break;
+        case E_UKIT_PROPERTY_TYPE_UINT32:
+          printf("\t%s = [%llu]\n", (char*)key, (long long unsigned)e_ukit_property_uint32_get(&props, key, &err));
+          break;
+        case E_UKIT_PROPERTY_TYPE_UINT64:
+          printf("\t%s = [%llu]\n", (char*)key, (long long unsigned)e_ukit_property_uint64_get(&props, key, &err));
+          break;
+        case E_UKIT_PROPERTY_TYPE_INT64:
+          printf("\t%s = [%lld]\n", (char*)key, (long long int)e_ukit_property_int64_get(&props, key, &err));
+          break;
+        case E_UKIT_PROPERTY_TYPE_BOOL:
+          printf("\t%s = [%d]\n", (char*)key, e_ukit_property_bool_get(&props, key, &err));
+          break;
+        case E_UKIT_PROPERTY_TYPE_DOUBLE:
+          printf("\t%s = [%f]\n", (char*)key, e_ukit_property_double_get(&props, key, &err));
+          break;
+        case E_UKIT_PROPERTY_TYPE_STRLIST:
+          printf("\t%s = [", (char*)key);
+          strlist = e_ukit_property_strlist_get(&props, key, &err);
+          EINA_LIST_FOREACH(strlist, l, y)
+           printf("%s%s", y, (l->next) ? " " : "");
+          printf("]\n");
+          break;
+     }
+
+   return EINA_TRUE;
+}
+
+static void
+hash_props(void *user_data, void *reply_data, DBusError *error)
+{
+   printf("%s:\n", (char*)user_data);
+   E_Ukit_Get_All_Properties_Return *ret = reply_data;
+
+   if (!ret || dbus_error_is_set(error))
+     {
+        free(user_data);
+        dbus_error_free(error);
+        return;
+     }
+
+   eina_hash_foreach(ret->properties, print_prop, NULL);
+   printf("\n");
+   free(user_data);
+}
+
+static void
+test_mount(void *user_data, void *reply_data, DBusError *error)
+{
+   E_Ukit_Get_Property_Return *ret = reply_data;
+
+   if (!ret || dbus_error_is_set(error))
+     {
+        free(user_data);
+        dbus_error_free(error);
+        return;
+     }
+
+   if (ret->val.b)
+     {
+        printf("[%s] is mounted!\n\tGrabbing more stats to fill your screen...\n", (char*)user_data);
+        e_udisks_get_all_properties(econ, user_data, hash_props, strdup(user_data));
+     }
+   else printf("[%s] is not mounted!\n", (char*)user_data);
+   free(user_data);
+}
+
+static void
+print_devs(void *user_data, void *reply_data, DBusError *error)
+{
+   E_Ukit_Get_All_Devices_Return *ret = reply_data;
+   Eina_List *l;
+   char *udi;
+
+   if (!ret || !ret->strings || dbus_error_is_set(error))
+     {
+        free(user_data);
+        dbus_error_free(error);
+        return;
+     }
+
+   EINA_LIST_FOREACH(ret->strings, l, udi)
+     {
+        if (!strcmp((char*)user_data, "disks"))
+          e_udisks_get_property(econ, udi, "DeviceIsMounted", test_mount, strdup(udi));
+        else
+          e_upower_get_all_properties(econ, udi, hash_props, strdup(udi));
+     }
+   free(user_data);
+}
+
+static Eina_Bool
+my_quit(__UNUSED__ void *data)
+{
+   ecore_main_loop_quit();
+   return ECORE_CALLBACK_CANCEL;
+}
+
+int main(void)
+{
+   ecore_init();
+   eina_init();
+   e_dbus_init();
+   e_ukit_init();
+
+   econ = e_dbus_bus_get(DBUS_BUS_SYSTEM);
+   if (econ)
+     {
+        e_udisks_get_all_devices(econ, print_devs, strdup("disks"));
+        e_upower_get_all_devices(econ, print_devs, strdup("power"));
+     }
+   /*add a short timer to quit to try and ensure that all the tests run*/
+   ecore_timer_add(1, my_quit, NULL);
+   ecore_main_loop_begin();
+
+   if (econ) e_dbus_connection_close(econ);
+   e_ukit_shutdown();
+   e_dbus_shutdown();
+   eina_shutdown();
+   ecore_shutdown();
+   
+   return 0;
+}
diff --git a/src/bin/logo.png b/src/bin/logo.png
new file mode 100644 (file)
index 0000000..d42aeb4
Binary files /dev/null and b/src/bin/logo.png differ
diff --git a/src/bin/notification_daemon.c b/src/bin/notification_daemon.c
new file mode 100644 (file)
index 0000000..aa9f0a6
--- /dev/null
@@ -0,0 +1,196 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+
+#include <Ecore.h>
+#include <E_Notification_Daemon.h>
+
+typedef struct Daemon_Data Daemon_Data;
+typedef struct Timer_Data Timer_Data;
+
+struct Timer_Data
+{
+  Daemon_Data *d;
+  E_Notification *n;
+};
+
+struct Daemon_Data
+{
+  E_Notification_Daemon *daemon;
+  Eina_List *open_notes;
+
+  Eina_List *history;
+  int history_start;
+  int max_history_length;
+  int default_timeout;
+
+  int next_id;
+};
+
+void
+daemon_note_close(Daemon_Data *dd, E_Notification *n, int reason)
+{
+  printf("Close notification #%d\n", e_notification_id_get(n));
+
+  if (eina_list_data_find(dd->open_notes, n))
+  {
+    dd->open_notes = eina_list_remove(dd->open_notes, n);
+    e_notification_closed_set(n, 1);
+    e_notification_daemon_signal_notification_closed(dd->daemon, e_notification_id_get(n), reason);
+    e_notification_unref(n);
+  }
+}
+
+Eina_Bool
+cb_note_close_timer(void *data)
+{
+  Timer_Data *td = data;
+
+  if (!e_notification_closed_get(td->n))
+    daemon_note_close(td->d, td->n, E_NOTIFICATION_CLOSED_EXPIRED);
+
+  e_notification_unref(td->n);
+  free(td);
+
+  return ECORE_CALLBACK_CANCEL;
+}
+
+void
+daemon_note_show(Daemon_Data *d, E_Notification *n)
+{
+  e_notification_ref(n);
+  d->open_notes = eina_list_append(d->open_notes, n);
+  e_notification_ref(n);
+  d->history = eina_list_append(d->history, n);
+
+  // adjust history
+  if ((int) eina_list_count(d->history) > d->max_history_length)
+  {
+    E_Notification *old;
+    old = eina_list_data_get(d->history);
+    d->history = eina_list_remove_list(d->history, d->history);
+    d->history_start = e_notification_id_get(old) + 1;
+    e_notification_unref(old);
+  }
+
+  {
+    int timeout;
+
+    timeout = e_notification_timeout_get(n);
+    Timer_Data *td = calloc(1, sizeof(Timer_Data));
+    td->d = d;
+    e_notification_ref(n);
+    td->n = n;
+    ecore_timer_add(timeout == -1 ? d->default_timeout : (float)timeout / 1000, cb_note_close_timer, td);
+  }
+
+  printf("Received notification from %s:\n%s\n%s\n\n",
+    e_notification_app_name_get(n),
+    e_notification_summary_get(n), e_notification_body_get(n)
+  );
+}
+
+E_Notification *
+daemon_note_open_find(Daemon_Data *d, unsigned int id)
+{
+  E_Notification *n;
+  Eina_List *l;
+
+  EINA_LIST_FOREACH(d->open_notes, l, n)
+    if (e_notification_id_get(n) == id) return n;
+
+  return NULL;
+}
+
+E_Notification *
+daemon_note_history_find(Daemon_Data *d, int id)
+{
+  if (id < d->history_start) return NULL;
+
+  // TODO
+
+  return NULL;
+}
+
+
+
+int
+cb_notify(E_Notification_Daemon *ndaemon, E_Notification *n)
+{
+  Daemon_Data *dd;
+  unsigned int replaces_id;
+  unsigned int new_id;
+
+  dd = e_notification_daemon_data_get(ndaemon);
+  replaces_id = e_notification_replaces_id_get(n);
+  if (replaces_id)
+  {
+    // close old one flagged as replaced
+  }
+
+  new_id = dd->next_id++;
+  e_notification_id_set(n, new_id);
+
+  daemon_note_show(dd, n);
+
+  return new_id;
+}
+
+void
+cb_close_notification(E_Notification_Daemon *ndaemon, unsigned int notification_id)
+{
+  Daemon_Data *dd;
+  E_Notification *n;
+  dd = e_notification_daemon_data_get(ndaemon);
+  n = daemon_note_open_find(dd, notification_id);
+  if (n)
+    daemon_note_close(dd, n, E_NOTIFICATION_CLOSED_REQUESTED);
+  // else send error?
+}
+
+
+int
+main()
+{
+  E_Notification_Daemon *d;
+  E_Notification *n;
+  Daemon_Data *dd;
+
+
+  ecore_init();
+
+  dd = calloc(1, sizeof(Daemon_Data));
+  dd->open_notes = NULL;
+  dd->history = NULL;
+  dd->next_id = dd->history_start = 1;
+  dd->max_history_length = 5;
+  dd->default_timeout = 5;
+
+  /* set up the daemon */
+  d = e_notification_daemon_add("e_notification_module", "Enlightenment");
+  e_notification_daemon_data_set(d, dd);
+  dd->daemon = d;
+  e_notification_daemon_callback_notify_set(d, cb_notify);
+  e_notification_daemon_callback_close_notification_set(d, cb_close_notification);
+
+  ecore_main_loop_begin();
+  while (dd->open_notes)
+    {
+       n = eina_list_data_get(dd->open_notes);
+       e_notification_unref(n);
+       dd->open_notes = eina_list_remove_list(dd->open_notes, dd->open_notes);
+    }
+  while (dd->history)
+    {
+       n = eina_list_data_get(dd->history);
+       e_notification_unref(n);
+       dd->history = eina_list_remove_list(dd->history, dd->history);
+    }
+  free(dd);
+  e_notification_daemon_free(d);
+  ecore_shutdown();
+
+  return 0;
+}
diff --git a/src/bin/notify-send.c b/src/bin/notify-send.c
new file mode 100644 (file)
index 0000000..4c89430
--- /dev/null
@@ -0,0 +1,191 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <getopt.h>
+#include <sysexits.h>
+
+#include <Ecore.h>
+#include <E_Notify.h>
+
+#define S(X) #X
+
+#define CHECK(X) do { \
+  if (!X) \
+    { \
+       fprintf(stderr, "%s:%i: Error calling %s!\n", __FILE__, __LINE__, S(X)); \
+       exit(1); \
+    } \
+} while (0)
+
+void
+version(void)
+{
+  printf("e-notify-send "VERSION"\n");
+}
+
+void
+usage(void)
+{
+  printf("Usage:\n"
+         "  e-notify-send [OPTION...] <SUMMARY> [BODY] - create a notification\n"
+         "\n"
+         "Help Options:\n"
+         "  -?, --help                        Show help options\n"
+         "\n"
+         "Application Options:\n"
+         "  -n, --name=NAME                   Specifies the application name to use (default is e-notify-send).\n"
+         "  -u, --urgency=LEVEL               Specifies the urgency level (low, normal, critical).\n"
+         "  -t, --expire-time=TIME            Specifies the timeout in milliseconds at which to expire the notification.\n"
+         "  -r, --replace=ID                  Specifies the ID of notification to replace.\n"
+         "  -p, --print-id                    Prints the ID of notification to STDOUT.\n"
+         "  -i, --icon=ICON                   Specifies an icon filename or stock icon to display.\n"
+         "  -c, --category=TYPE               Specifies the notification category.\n"
+         "  -v, --version                     Version of the package.\n"
+         "\n");
+}
+
+int
+read_int_arg(long long *result, const char *name, intmax_t min, intmax_t max)
+{
+  char *endptr;
+
+  errno = 0;  
+  *result = strtoll(optarg, &endptr, 10);
+  if ((errno != 0 && *result == 0) || endptr == optarg) 
+    {
+       fprintf(stderr, "Cannot parse integer value '%s' for %s\n", optarg, name);
+       return 0;
+    }
+  else if (*result > max || *result < min)
+    {
+       fprintf(stderr, "Integer value '%s' for %s out of range\n", optarg, name);
+       return 0;
+    }
+
+  return 1;
+}
+
+void 
+send_cb(void *user_data __UNUSED__, void *method_return, DBusError *error __UNUSED__)
+{
+   E_Notification_Return_Notify *r = method_return;
+
+   if(!r)
+     return;
+
+   printf("%u\n", r->notification_id );
+
+   ecore_main_loop_quit();
+}
+
+int
+main(int argc, char **argv)
+{
+  int ch;
+  long long value;
+  int print_id = 0;
+  E_Notification *n;
+
+  CHECK(eina_init());
+  CHECK(ecore_init());
+  CHECK(e_notification_init());
+  n = e_notification_new();
+  e_notification_app_name_set(n, "e-notify-send");
+  e_notification_timeout_set(n, -1);
+
+  /* options descriptor */
+  static struct option longopts[] = {
+      { "help",        no_argument,            NULL,           '?' },
+      { "name",        required_argument,      NULL,           'n' },
+      { "urgency",     required_argument,      NULL,           'u' },
+      { "expire-time", required_argument,      NULL,           't' },
+      { "replace",     required_argument,      NULL,           'r' },
+      { "print-id",    no_argument,            NULL,           'p' },
+      { "icon",        required_argument,      NULL,           'i' },
+      { "category",    required_argument,      NULL,           'c' },
+      { "version",     no_argument,            NULL,           'v' },
+      { NULL,          0,                      NULL,             0 }
+  };
+
+  while ((ch = getopt_long(argc, argv, "p?vn:u:t:r:i:c:", longopts, NULL)) != -1)
+    switch (ch) {
+    case '?':
+      usage();
+      return EXIT_SUCCESS;
+      break;
+    case 'v':
+      version();
+      return EXIT_SUCCESS;
+      break;
+    case 'n':
+      e_notification_app_name_set(n, optarg);
+      break;
+    case 'u':
+      if (!strcasecmp(optarg, "low"))
+        e_notification_hint_urgency_set(n, E_NOTIFICATION_URGENCY_LOW);
+      else if (!strcasecmp(optarg, "normal"))
+        e_notification_hint_urgency_set(n, E_NOTIFICATION_URGENCY_NORMAL);
+      else if (!strcasecmp(optarg, "critical"))
+        e_notification_hint_urgency_set(n, E_NOTIFICATION_URGENCY_CRITICAL);
+      else
+        printf("Urgency level must be: low, normal or critical\n");
+      break;
+    case 't':
+      if (!read_int_arg(&value, "-t", INT_MIN, INT_MAX))
+        return EXIT_FAILURE;
+      else 
+        e_notification_timeout_set(n, (int)value);
+      break;
+    case 'r':
+      if (!read_int_arg(&value, "-r", 0, UINT_MAX))
+        return EXIT_FAILURE;
+      else
+           e_notification_replaces_id_set(n, (unsigned int)value);
+      break;
+    case 'i':
+      e_notification_app_icon_set(n, optarg);
+      break;
+    case 'c':
+      e_notification_hint_category_set(n, optarg);
+      break;
+    case 'p':
+      print_id = 1;
+      break;
+    default:
+      usage();
+      return EXIT_FAILURE;
+    }
+  argc -= optind;
+  argv += optind;
+
+  if (argc < 1)
+    {
+      usage();
+      return EXIT_FAILURE;
+    }
+
+  e_notification_summary_set(n, argv[0]);
+  if (argc > 1) e_notification_body_set(n, argv[1]);
+
+
+  if (print_id)
+    {
+       e_notification_send(n, send_cb, NULL);
+       ecore_main_loop_begin();
+    }
+  else
+    e_notification_send(n, NULL, NULL);
+
+  e_notification_unref(n);
+  e_notification_shutdown();
+  ecore_shutdown();
+  eina_shutdown();
+
+  return EXIT_SUCCESS;
+}
diff --git a/src/bin/notify.c b/src/bin/notify.c
new file mode 100644 (file)
index 0000000..375c632
--- /dev/null
@@ -0,0 +1,125 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <Evas.h>
+#include <Ecore.h>
+#include <Ecore_Evas.h>
+#include <E_DBus.h>
+#include <E_Notify.h>
+
+#define LOGO PACKAGE_DATA_DIR "/logo.png"
+
+void
+cb_sent(void *data __UNUSED__, void *ret, DBusError *err)
+{
+  E_Notification_Return_Notify *notify;
+  notify = ret;
+  if (notify) 
+  {
+    printf("id: %d\n", notify->notification_id);
+  }
+  else if (dbus_error_is_set(err))
+  {
+    printf("Error: %s\n", err->message);
+  }
+}
+
+Eina_Bool
+cb_timer(void *data __UNUSED__)
+{
+  E_Notification *n;
+  char buf[1024];
+  static int num = 0;
+  static const char *icons[] = {
+    "xterm",
+    "firefox",
+    "gvim",
+    "e"
+  };
+
+  snprintf(buf, sizeof(buf), "<i>%s</i> says <b>Hello</b> #%d", icons[num % 4], num % 4); 
+  n = e_notification_full_new(icons[num % 4], 0, (icons[num % 4][0] != 'e') ? icons[num % 4] : NULL, "Summary", buf, -1);
+
+  if (!e_notification_app_icon_get(n))
+    {
+       Ecore_Evas *ee;
+       Evas_Object *img;
+       E_Notification_Image *i;
+       ee = ecore_evas_buffer_new(1, 1);
+       if (ee)
+         {
+            img = evas_object_image_add(ecore_evas_get(ee));
+            evas_object_image_file_set(img, LOGO, NULL);
+            if (evas_object_image_load_error_get(img) != EVAS_LOAD_ERROR_NONE)
+              evas_object_image_file_set(img, "logo.png", NULL);
+            if (evas_object_image_load_error_get(img) != EVAS_LOAD_ERROR_NONE)
+              {
+                 fprintf(stderr, "ERROR LOADING IMAGE: %s\n", LOGO);
+                 evas_object_del(img);
+                 img = NULL;
+              }
+            else
+              ecore_evas_manual_render(ee);
+
+            i = e_notification_image_new();
+            if (e_notification_image_init(i, img))
+              e_notification_hint_image_data_set(n, i);
+           evas_object_del(img);
+           ecore_evas_free(ee);
+         }
+    }
+
+  e_notification_send(n, cb_sent, NULL);
+  e_notification_unref(n);
+  num++;
+
+  return ECORE_CALLBACK_RENEW;
+}
+
+void
+cb_action_invoked(void *data __UNUSED__, int type __UNUSED__, void *event)
+{
+  E_Notification_Event_Action_Invoked *ev;
+
+  ev = event;
+  printf("Action (%d): %s\n", ev->notification_id, ev->action_id);
+  free(ev);
+}
+
+void
+cb_note_closed(void *data __UNUSED__, int type __UNUSED__, void *event)
+{
+  E_Notification_Event_Notification_Closed *ev;
+  static const char *reasons[] = {
+    "Expired",
+    "Dismissed",
+    "Requested",
+    "Undefined"
+  };
+
+  ev = event;
+  printf("Note %d closed: %s\n", ev->notification_id, reasons[ev->reason]);
+  free(ev);
+}
+
+int
+main()
+{
+  int ret = 0;
+  ecore_init();
+  ecore_evas_init();
+  if (e_notification_init())
+  {
+    ecore_timer_add(1, cb_timer, NULL);
+    ecore_main_loop_begin();
+    e_notification_shutdown();
+  }
+
+  ecore_evas_shutdown();
+  ecore_shutdown();
+  return ret;
+}
diff --git a/src/bin/performance.c b/src/bin/performance.c
new file mode 100644 (file)
index 0000000..b1d1607
--- /dev/null
@@ -0,0 +1,573 @@
+#include <stdio.h>
+#include <Eina.h>
+#include <Ecore.h>
+#include <Evas.h>
+#include <Ecore_Evas.h>
+#include <E_DBus.h>
+#include <Elementary.h>
+#include <time.h>
+
+#define SPECTATOR_MODE 1//in spectator mode messages are send as signals
+
+#define SIZE_W 800
+#define SIZE_H 600
+
+#define SHIP_SIZE 50
+
+#define BUS_NAME_SERVER "com.profusion.benchmak.server"
+#define PATH_NAME_SERVER "/com/profusion/benchmak/server"
+#define IFACE_NAME_SERVER "com.profusion.benchmak.server.game"
+
+#define BUS_NAME_CLIENT "com.profusion.benchmark.client"
+#define PATH_NAME_CLIENT "/com/profusion/benchmak/client"
+#define IFACE_NAME_CLIENT "com.profusion.benchmark.client.game"
+
+#define MOVEMENT_DELAY 0.01//10ms between movements
+#define MOVEMENT_Y 5//increment/decrement ship movement
+
+#define MOVEMENT_BULLET 10
+#define BULLET_SIZE_W 100
+#define BULLET_SIZE_H 50
+
+#define TIMEOUT -1
+
+E_DBus_Connection *conn;
+E_DBus_Object *obj_path;
+Evas_Object *client_ship, *server_ship;
+char can_join = 1;
+char player;
+int player_y_start;
+int player_y_end;
+int player_x;
+int action;//1 up, 2 down
+
+Evas_Object *win;
+
+typedef struct _bullet
+  {
+     Evas_Object *o;
+     int x;
+     int y;
+     char direction;
+  } bullet;
+
+
+typedef struct _EDBus_Method
+  {
+     char *member;
+     char *signature;
+     char *reply_signature;
+     E_DBus_Method_Cb func;
+     char *c_symbol;
+     int annotations;
+  } EDBus_Method;
+
+typedef struct _EDBus_Signal
+  {
+     char *name;
+     char *signature;
+     char *c_symbol;
+     int annotations;
+  } EDBus_Signal;
+
+static void obj_register(char *path_name, char *iface_name, EDBus_Method *methods, EDBus_Signal *signals);
+
+static Eina_Bool _move_bullet(void *context)
+{
+   bullet *b = context;
+
+   if (b->direction == '+')
+     {
+        b->x += MOVEMENT_BULLET;
+        evas_object_move(b->o, b->x, b->y);
+        if ((b->x + MOVEMENT_BULLET) < SIZE_W)
+           return ECORE_CALLBACK_RENEW;
+     }
+   else
+     {
+        b->x -= MOVEMENT_BULLET;
+        evas_object_move(b->o, b->x, b->y);
+        if ((b->x - MOVEMENT_BULLET) > 0)
+           return ECORE_CALLBACK_RENEW;
+     }
+
+   evas_object_hide(b->o);
+   evas_object_del(b->o);
+   free(b);
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_shoot(char _player, int x, int y)
+{
+   bullet *b = malloc(sizeof(bullet));
+
+   if (_player == 1) b->direction = '+';
+   else b->direction = '-';
+
+   b->x = x;
+   b->y = y;
+
+   b->o = elm_progressbar_add(win);
+   elm_progressbar_pulse(b->o, TRUE);
+   evas_object_resize(b->o, BULLET_SIZE_W, BULLET_SIZE_H);
+   evas_object_move(b->o, x, y);
+
+   evas_object_show(b->o);
+
+   ecore_timer_add(0.2, _move_bullet, b);
+}
+
+static void
+_dbus_error_check(DBusError *error)
+{
+   if (dbus_error_is_set(error))
+     {
+        printf("dbus error\nName: %s\nDescription: %s\n", error->name,
+               error->message);
+        elm_exit();
+     }
+}
+
+void
+create_ship(Evas_Object **_obj, Evas *canvas, char _player)
+{
+   Evas_Object *o;
+
+   o = evas_object_polygon_add(canvas);
+
+   if (_player == 1)
+     {
+        evas_object_polygon_point_add(o, 0, SIZE_H - SHIP_SIZE);
+        evas_object_polygon_point_add(o, SHIP_SIZE / 2, SIZE_H - (SHIP_SIZE / 2));
+        evas_object_polygon_point_add(o, 0, SIZE_H);
+
+        evas_object_color_set(o, 255, 0, 0, 255);
+     }
+   else
+     {
+        evas_object_polygon_point_add(o, SIZE_W, 0);
+        evas_object_polygon_point_add(o, SIZE_W - (SHIP_SIZE / 2), SHIP_SIZE / 2);
+        evas_object_polygon_point_add(o, SIZE_W, SHIP_SIZE);
+
+        evas_object_color_set(o, 0, 0, 255, 255);
+     }
+   evas_object_show(o);
+
+   *_obj = o;
+}
+
+static void
+update(char _player, int x, int y)
+{
+   if (_player == 1)
+      evas_object_move(server_ship, x, y);
+   else
+      evas_object_move(client_ship, x, y);
+}
+
+static void
+_cb_move_ack(void *data, DBusMessage *msg, DBusError *error)
+{
+   _dbus_error_check(error);
+}
+
+#if SPECTATOR_MODE == 1
+static void
+send_my_position()
+{
+   DBusMessage *msg;
+
+   if (player == 1)
+     msg = dbus_message_new_signal(PATH_NAME_SERVER, IFACE_NAME_SERVER,
+                                   "moveOfServer");
+   else
+     msg = dbus_message_new_signal(PATH_NAME_CLIENT, IFACE_NAME_CLIENT,
+                                   "moveOfClient");
+
+   dbus_message_append_args(msg, DBUS_TYPE_INT32, &player_x, DBUS_TYPE_INT32,
+                            &player_y_start, DBUS_TYPE_INVALID);
+   e_dbus_message_send(conn, msg, _cb_move_ack, TIMEOUT, NULL);
+   dbus_message_unref(msg);
+}
+#else
+static void
+send_my_position()
+{
+   DBusMessage *msg;
+
+   if (player == 1)
+     msg = dbus_message_new_method_call(BUS_NAME_CLIENT, PATH_NAME_CLIENT,
+                                        IFACE_NAME_CLIENT, "moveOfServer");
+   else
+     msg = dbus_message_new_method_call(BUS_NAME_SERVER, PATH_NAME_SERVER,
+                                        IFACE_NAME_SERVER, "moveOfClient");
+
+   dbus_message_append_args(msg, DBUS_TYPE_INT32, &player_x, DBUS_TYPE_INT32,
+                            &player_y_start, DBUS_TYPE_INVALID);
+   e_dbus_message_send(conn, msg, _cb_move_ack, TIMEOUT, NULL);
+   dbus_message_unref(msg);
+}
+#endif
+
+static Eina_Bool
+_movement(void *data)
+{
+   if (action == 1)
+     {
+        if ((player_y_start - MOVEMENT_Y) >= 0)
+          {
+             player_y_start -= MOVEMENT_Y;
+             player_y_end = player_y_start + SHIP_SIZE;
+             send_my_position();
+             update(player, player_x, player_y_start);
+             if ((rand() % 6) == 5)
+               _shoot(player, player_x, player_y_start);
+             return ECORE_CALLBACK_RENEW;
+          }
+      else
+        {
+           action = 2;
+           return _movement(NULL);
+        }
+     }
+   else
+     {
+        if ((player_y_end + MOVEMENT_Y) <= SIZE_H)
+          {
+             player_y_end += MOVEMENT_Y;
+             player_y_start = player_y_end - SHIP_SIZE;
+             send_my_position();
+             update(player, player_x, player_y_start);
+             if ((rand() % 6) == 5)
+               _shoot(player, player_x, player_y_start);
+             return ECORE_CALLBACK_RENEW;
+          }
+      else
+        {
+           action = 1;
+           return _movement(NULL);
+        }
+   }
+}
+
+void
+create_auto_move_event(char p)
+{
+   player = action = p;
+   player_y_start = 0;
+   player_y_end = SHIP_SIZE;
+
+   if (player == 1)
+     {
+        player_x = 0;
+        player_y_start = SIZE_H - SHIP_SIZE;
+        player_y_end = SIZE_H;
+     }
+   else
+     {
+        player_x = SIZE_W - (SHIP_SIZE / 2);
+        player_y_start = SIZE_H - SHIP_SIZE;
+        player_y_end = SIZE_H;
+
+        player_y_start = 0;
+        player_y_end = SHIP_SIZE;
+     }
+
+   ecore_timer_add(MOVEMENT_DELAY, _movement, NULL);
+}
+
+static DBusMessage *
+_move_(Evas_Object *ship, E_DBus_Object *_obj, DBusMessage *msg)
+{
+   DBusMessage *reply = dbus_message_new_method_return(msg);
+   int x, y;
+   DBusError new_err;
+
+   dbus_error_init(&new_err);
+   dbus_message_get_args(msg, &new_err, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
+                         &y, DBUS_TYPE_INVALID);
+   _dbus_error_check(&new_err);
+
+   evas_object_move(ship, x, y);
+
+   return reply;
+}
+
+#if SPECTATOR_MODE == 1
+static void
+_move_client(void *context, DBusMessage *msg)
+{
+   _move_(client_ship, NULL, msg);
+}
+
+static void
+_move_server(void *context, DBusMessage *msg)
+{
+   _move_(server_ship, NULL, msg);
+}
+#else
+static DBusMessage *
+_move_client(E_DBus_Object *obj, DBusMessage *msg)
+{
+   return _move_(client_ship, obj, msg);
+}
+
+static DBusMessage *
+_move_server(E_DBus_Object *obj, DBusMessage *msg)
+{
+   return _move_(server_ship, obj, msg);
+}
+#endif
+
+static DBusMessage *
+_can_join(E_DBus_Object *_obj, DBusMessage *msg)
+{
+   DBusMessage *reply = dbus_message_new_method_return(msg);
+
+   if (can_join)
+     {
+        dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &can_join,
+                                 DBUS_TYPE_INVALID);
+        can_join = 0;
+
+#if SPECTATOR_MODE == 1
+        e_dbus_signal_handler_add(conn, BUS_NAME_CLIENT, PATH_NAME_CLIENT,
+                                  IFACE_NAME_CLIENT, "moveOfClient",
+                                  _move_client, NULL);
+#endif
+
+        create_auto_move_event(1);
+        printf("game started\n");
+     }
+   else
+     {
+        dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &can_join,
+                                 DBUS_TYPE_INVALID);
+     }
+
+   return reply;
+}
+
+static void
+_cb_dbus_request_name_client(void *context, DBusMessage *msg, DBusError *err)
+{
+   DBusError new_err;
+   int flag;
+   _dbus_error_check(err);
+
+   dbus_error_init(&new_err);
+   dbus_message_get_args(msg, &new_err, DBUS_TYPE_UINT32, &flag,
+                         DBUS_TYPE_INVALID);
+
+   if (flag == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+     {
+        EDBus_Method table_methods[] =
+          {
+#if SPECTATOR_MODE == 0
+             { "moveOfServer", "ii", "", _move_server, "move_server", 0},
+#endif
+             { NULL, NULL, NULL, NULL, NULL, 0 }
+          };
+
+        EDBus_Signal table_signal[] =
+          {
+#if SPECTATOR_MODE == 1
+             { "moveOfClient", "ii", "move_client", 0 },
+#endif
+             { NULL, NULL, NULL, 0 }
+          };
+
+        /*e_dbus_interface_register(conn, PATH_NAME_CLIENT, IFACE_NAME_CLIENT,
+                                  table, table_signal, NULL, NULL);*/
+        obj_register(PATH_NAME_CLIENT, IFACE_NAME_CLIENT, table_methods, table_signal);
+
+#if SPECTATOR_MODE == 1
+        e_dbus_signal_handler_add(conn, BUS_NAME_SERVER, PATH_NAME_SERVER,
+                                  IFACE_NAME_SERVER, "moveOfServer",
+                                  _move_server, NULL);
+#endif
+
+        create_auto_move_event(2);
+        printf("game started\n");
+     }
+   else printf("dbus_request_name fail, the client name was already in use.\n");
+}
+
+static void
+_cb_can_join(void *data, DBusMessage *msg, DBusError *error)
+{
+   char bool;
+   DBusError new_err;
+
+   _dbus_error_check(error);
+
+   dbus_error_init(&new_err);
+   dbus_message_get_args(msg, &new_err, DBUS_TYPE_BOOLEAN, &bool,
+                         DBUS_TYPE_INVALID);
+   _dbus_error_check(&new_err);
+
+   if (bool)
+     {
+        e_dbus_request_name(conn, BUS_NAME_CLIENT, DBUS_NAME_FLAG_DO_NOT_QUEUE,
+                            _cb_dbus_request_name_client, NULL);
+     }
+   else
+     {
+#if SPECTATOR_MODE == 1
+        printf("Spectator mode\n");
+        e_dbus_signal_handler_add(conn, BUS_NAME_SERVER, PATH_NAME_SERVER,
+                                  IFACE_NAME_SERVER, "moveOfServer",
+                                  _move_server, NULL);
+        e_dbus_signal_handler_add(conn, BUS_NAME_CLIENT, PATH_NAME_CLIENT,
+                                  IFACE_NAME_CLIENT, "moveOfClient",
+                                  _move_client, NULL);
+#else
+        printf("server full, try later!\n");
+        elm_exit();
+#endif
+     }
+}
+
+static void
+_ask_if_can_join()
+{
+   DBusMessage *msg =
+            dbus_message_new_method_call(BUS_NAME_SERVER, PATH_NAME_SERVER,
+                                         IFACE_NAME_SERVER, "canJoin");
+   e_dbus_message_send(conn, msg, _cb_can_join, -1, NULL);
+   dbus_message_unref(msg);
+}
+
+static void
+_cb_dbus_request_name_server(void *context, DBusMessage *msg, DBusError *err)
+{
+   DBusError new_err;
+   int flag = 0;
+   _dbus_error_check(err);
+
+   dbus_error_init(&new_err);
+   dbus_message_get_args(msg, &new_err, DBUS_TYPE_UINT32, &flag,
+                         DBUS_TYPE_INVALID);
+
+   if (flag == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+     {
+        EDBus_Method table_methods[] =
+          {
+             { "canJoin", "", "b", _can_join, "can_join", 0 },
+#if SPECTATOR_MODE == 0
+             { "moveOfClient", "ii", "", _move_client, "move_client", 0},
+#endif
+             { NULL, NULL, NULL, NULL, NULL, 0 }
+          };
+
+       EDBus_Signal table_signal[] =
+          {
+#if SPECTATOR_MODE == 1
+             { "moveOfServer", "ii", "move_server", 0 },
+#endif
+             { NULL, NULL, NULL, 0 }
+          };
+
+       /*e_dbus_interface_register(conn, PATH_NAME_SERVER, IFACE_NAME_SERVER,
+                                 table, table_signal, NULL, NULL);*/
+       obj_register(PATH_NAME_SERVER, IFACE_NAME_SERVER, table_methods, table_signal);
+
+       printf("Waiting for another player\n");
+
+     }
+   else _ask_if_can_join();
+}
+
+static void
+obj_register(char *path_name, char *iface_name, EDBus_Method *methods, EDBus_Signal *signals)
+{
+   obj_path = e_dbus_object_add(conn, path_name, NULL);
+   E_DBus_Interface *iface = e_dbus_interface_new(iface_name);
+   const EDBus_Method *_method;
+   const EDBus_Signal *_signal;
+
+   e_dbus_object_interface_attach(obj_path, iface);
+   e_dbus_interface_unref(iface);
+
+   for (_method = methods; _method != NULL && _method->member != NULL; _method++)
+     e_dbus_interface_method_add(iface, _method->member,
+                                        _method->signature,
+                                        _method->reply_signature,
+                                        _method->func);
+
+   for (_signal = signals; _signal != NULL && _signal->name != NULL; _signal++)
+        e_dbus_interface_signal_add(iface, _signal->name, _signal->signature);
+}
+
+static void
+obj_unregister()
+{
+   if (!obj_path) return;
+   e_dbus_object_free(obj_path);
+}
+
+static void
+_mouse_handler(void *data, Evas *e, Evas_Object *_obj, void *event_info)
+{
+   Evas_Event_Mouse_Move *mouse_info = event_info;
+   Evas_Object *square = data;
+
+   evas_object_move(square, mouse_info->cur.canvas.x, mouse_info->cur.canvas.y);
+}
+
+static void
+on_done(void *data, Evas_Object *_obj, void *event_info)
+{
+   elm_exit();
+}
+
+int
+elm_main(int argc, char **argv)
+{
+   Evas *canvas;
+   Evas_Object *bg, *square;
+   srand(time(NULL));
+
+   e_dbus_init();
+
+   win = elm_win_add(NULL, "bg-plain", ELM_WIN_BASIC);
+   elm_win_title_set(win, "Benchmark");
+   evas_object_smart_callback_add(win, "delete,request", on_done, NULL);
+   elm_win_autodel_set(win, EINA_TRUE);
+   evas_object_resize(win, SIZE_W, SIZE_H);
+   canvas = evas_object_evas_get(win);
+
+   bg = elm_bg_add(win);
+   evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, bg);
+   elm_bg_color_set(bg, 255, 255, 255);
+   evas_object_show(bg);
+
+   square = evas_object_rectangle_add(canvas);
+   evas_object_resize(square, 30, 30);
+   evas_object_color_set(square, 0, 255, 0, 255);
+   evas_object_show(square);
+   evas_object_event_callback_add(bg, EVAS_CALLBACK_MOUSE_MOVE, _mouse_handler,
+                                  square);
+
+   create_ship(&client_ship, canvas, 2);
+   create_ship(&server_ship, canvas, 1);
+
+   conn = e_dbus_bus_get(DBUS_BUS_SESSION);
+
+   e_dbus_request_name(conn, BUS_NAME_SERVER, DBUS_NAME_FLAG_DO_NOT_QUEUE,
+                       _cb_dbus_request_name_server, NULL);
+
+   evas_object_show(win);
+
+   elm_run();
+   elm_shutdown();
+   /*e_dbus_interface_unregister(conn, PATH_NAME_CLIENT);
+   e_dbus_interface_unregister(conn, PATH_NAME_SERVER);*/
+   obj_unregister();
+   e_dbus_shutdown();
+
+   return 0;
+}
+ELM_MAIN()
diff --git a/src/bin/test.c b/src/bin/test.c
new file mode 100644 (file)
index 0000000..3b298c1
--- /dev/null
@@ -0,0 +1,118 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _WIN32
+# define DBUS_API_SUBJECT_TO_CHANGE
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <Ecore.h>
+
+#include "E_DBus.h"
+
+void
+copy_message(DBusMessageIter *from, DBusMessageIter *to)
+{
+  int type;
+  printf("  copy message\n");
+  while((type = dbus_message_iter_get_arg_type(from)) != DBUS_TYPE_INVALID)
+  {
+    printf("  copy type: %c\n", type);
+    if (dbus_type_is_basic(type))
+    {
+      /* XXX is int64 big enough to hold all basic types? */
+      dbus_int64_t val;
+      dbus_message_iter_get_basic(from, &val);
+      dbus_message_iter_append_basic(to, type, &val);
+    }
+    else if (dbus_type_is_container(type))
+    {
+      int subtype;
+
+      subtype = dbus_message_iter_get_element_type(from);
+      if (type == DBUS_TYPE_ARRAY && dbus_type_is_fixed(subtype))
+      {
+        int n;
+        void *val;
+        dbus_message_iter_get_fixed_array(from, &val, &n);
+        dbus_message_iter_append_fixed_array(to, subtype, val, n);
+      }
+      else
+      {
+        DBusMessageIter fsub, tsub;
+        char *sig;
+        dbus_message_iter_recurse(from, &fsub);
+        sig = dbus_message_iter_get_signature(&fsub);
+        if (dbus_message_iter_open_container(to, type, sig, &tsub))
+        {
+          copy_message(&fsub, &tsub);
+          dbus_message_iter_close_container(to, &tsub);
+        }
+        else
+        {
+          printf("ERR: container open failed\n");
+        }
+      }
+    }
+    dbus_message_iter_next(from);
+  }
+}
+
+DBusMessage *
+cb_repeat(E_DBus_Object *obj __UNUSED__, DBusMessage *msg)
+{
+  DBusMessage *reply;
+  DBusMessageIter from, to;
+
+  printf("\n\nREPEAT\n--------\n");
+  reply = dbus_message_new_method_return(msg);
+  dbus_message_iter_init(msg, &from);
+  dbus_message_iter_init_append(reply, &to);
+
+  copy_message(&from, &to);
+  return reply;
+}
+
+void
+cb_request_name(void *data __UNUSED__, DBusMessage *msg __UNUSED__, DBusError *err __UNUSED__)
+{
+  // XXX check that this actually succeeded and handle errors...
+  printf("request name\n");
+}
+
+int
+_setup(E_DBus_Connection *conn)
+{
+  E_DBus_Object *repeater;
+  E_DBus_Interface *iface;
+  e_dbus_request_name(conn, "org.e.Repeater", 0, cb_request_name, NULL);
+  repeater = e_dbus_object_add(conn, "/org/e/Repeater", NULL);
+  iface = e_dbus_interface_new("org.e.Repeater");
+  e_dbus_interface_method_add(iface, "Repeat", NULL, NULL, cb_repeat);
+  e_dbus_object_interface_attach(repeater, iface);
+  return 1;
+}
+
+int
+main ()
+{
+  E_DBus_Connection *conn;
+  ecore_init();
+  e_dbus_init();
+
+  conn = e_dbus_bus_get(DBUS_BUS_SESSION);
+  if (conn)
+  {
+    if (_setup(conn)) ecore_main_loop_begin();
+    e_dbus_connection_close(conn);
+  }
+
+  e_dbus_shutdown();
+  ecore_shutdown();
+
+  return 0;
+}
diff --git a/src/bin/test_client.c b/src/bin/test_client.c
new file mode 100644 (file)
index 0000000..48aaf71
--- /dev/null
@@ -0,0 +1,75 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+
+#include <Ecore.h>
+#include <E_DBus.h>
+
+#define NUM_LOOPS 10000
+
+static dbus_uint32_t msg_num = 0;
+
+void
+cb_reply(void *data __UNUSED__, DBusMessage *reply, DBusError *error)
+{
+  dbus_uint32_t val;
+  if (dbus_error_is_set(error))
+  {
+    printf("Error: %s - %s\n", error->name, error->message);
+    return;
+  }
+
+  dbus_message_get_args(reply, error, DBUS_TYPE_UINT32, &val, DBUS_TYPE_INVALID);
+  printf("Received: %d\n", val);
+  if (val == NUM_LOOPS - 1) ecore_main_loop_quit();
+}
+
+Eina_Bool
+send_message(void *data)
+{
+
+  DBusMessage *msg;
+  E_DBus_Connection *conn;
+
+  conn = data;
+
+  msg = dbus_message_new_method_call(
+    "org.e.Repeater",
+    "/org/e/Repeater",
+    "org.e.Repeater",
+    "Repeat"
+  );
+
+  dbus_message_append_args(msg, DBUS_TYPE_UINT32, &msg_num, DBUS_TYPE_INVALID);
+  msg_num++;
+  e_dbus_message_send(conn, msg, cb_reply, -1, NULL);
+  dbus_message_unref(msg);
+  printf("Sent: %d\n", msg_num);
+  return ECORE_CALLBACK_RENEW;
+}
+
+int
+main()
+{
+  E_DBus_Connection *conn;
+  int ret = 0;
+  ecore_init();
+  e_dbus_init();
+
+  conn = e_dbus_bus_get(DBUS_BUS_SESSION);
+  if (conn)
+    ecore_timer_add(0.0, send_message, conn);
+  else
+  {
+    printf("Error: could not connect to session bus.\n");
+    ret = 1;
+  }
+
+  ecore_main_loop_begin();
+
+  e_dbus_shutdown();
+  ecore_shutdown();
+  return ret;
+}
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
new file mode 100644 (file)
index 0000000..f4ccefc
--- /dev/null
@@ -0,0 +1,27 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+SUBDIRS = dbus
+
+if BUILD_EBLUEZ
+SUBDIRS += bluez
+endif
+
+if BUILD_ECONNMAN0_7X
+SUBDIRS += connman0_7x
+endif
+
+if BUILD_EHAL
+SUBDIRS += hal
+endif
+
+if BUILD_ENOTIFY
+SUBDIRS += notification
+endif
+
+if BUILD_EOFONO
+SUBDIRS += ofono
+endif
+
+if BUILD_EUKIT
+SUBDIRS += ukit
+endif
diff --git a/src/lib/bluez/E_Bluez.h b/src/lib/bluez/E_Bluez.h
new file mode 100644 (file)
index 0000000..094fd91
--- /dev/null
@@ -0,0 +1,157 @@
+#ifndef E_BLUEZ_H
+#define E_BLUEZ_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+#include <E_DBus.h>
+
+/**
+ * @defgroup EBluez_Group EBluez
+ *
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Ecore Events */
+extern int E_BLUEZ_EVENT_MANAGER_IN;
+extern int E_BLUEZ_EVENT_MANAGER_OUT;
+extern int E_BLUEZ_EVENT_ELEMENT_ADD;
+extern int E_BLUEZ_EVENT_ELEMENT_DEL;
+extern int E_BLUEZ_EVENT_ELEMENT_UPDATED;
+extern int E_BLUEZ_EVENT_DEVICE_FOUND;
+// TODO: extern int E_BLUEZ_EVENT_DEVICE_DISAPPEARED;
+
+typedef struct _E_Bluez_Element        E_Bluez_Element;
+typedef struct _E_Bluez_Array          E_Bluez_Array;
+typedef struct _E_Bluez_Device_Found   E_Bluez_Device_Found;
+
+struct _E_Bluez_Element
+{
+   const char            *path;
+   const char            *interface;
+   E_DBus_Signal_Handler *signal_handler;
+   E_DBus_Signal_Handler *device_found_handler;
+   Eina_Inlist           *props;
+
+   /* private */
+   struct
+   {
+      Eina_Inlist *properties_get;
+      Eina_Inlist *property_set;
+      Eina_Inlist *agent_register;
+      Eina_Inlist *agent_unregister;
+      Eina_Inlist *start_discovery;
+      Eina_Inlist *stop_discovery;
+      Eina_Inlist *create_paired_device;
+   } _pending;
+   struct
+   {
+      Ecore_Idler *changed;
+   } _idler;
+   Eina_Inlist *_listeners;
+   int          _references;
+};
+
+struct _E_Bluez_Array
+{
+   int         type;
+   Eina_Array *array;
+};
+
+struct _E_Bluez_Device_Found
+{
+   E_Bluez_Element *adapter;
+   const char      *name;
+   E_Bluez_Array   *array;
+};
+
+/* General Public API */
+EAPI unsigned int         e_bluez_system_init(E_DBus_Connection *edbus_conn) EINA_ARG_NONNULL(1);
+EAPI unsigned int         e_bluez_system_shutdown(void);
+
+/* Manager Methods */
+EAPI E_Bluez_Element *    e_bluez_manager_get(void) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_manager_default_adapter(E_DBus_Method_Return_Cb cb, void *data) EINA_WARN_UNUSED_RESULT;
+
+/* Adapter Methods */
+EAPI E_Bluez_Element *    e_bluez_adapter_get(const char *path) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool            e_bluez_adapter_agent_register(E_Bluez_Element *element, const char *object_path, const char *capability, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_adapter_agent_unregister(E_Bluez_Element *element, const char *object_path, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_adapter_address_get(const E_Bluez_Element *element, const char **address) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_adapter_name_get(const E_Bluez_Element *element, const char **name) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_adapter_name_set(E_Bluez_Element *element, const char *name, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1,2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_adapter_powered_get(const E_Bluez_Element *element, Eina_Bool *powered) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_adapter_powered_set(E_Bluez_Element *profile, Eina_Bool powered, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_adapter_discoverable_get(const E_Bluez_Element *element, Eina_Bool *discoverable) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_adapter_discoverable_set(E_Bluez_Element *profile, Eina_Bool discoverable, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_adapter_discoverable_timeout_get(const E_Bluez_Element *element, unsigned int *timeout) EINA_ARG_NONNULL(1,2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_adapter_discoverable_timeout_set(E_Bluez_Element *element, unsigned int timeout, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_adapter_discovering_get(const E_Bluez_Element *element, Eina_Bool *discovering) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_adapter_start_discovery(E_Bluez_Element *element, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_adapter_stop_discovery(E_Bluez_Element *element, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_adapter_create_paired_device(E_Bluez_Element *element, const char *object_path, const char *capability, const char *device, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2, 4) EINA_WARN_UNUSED_RESULT;
+
+/* Device Found Methods */
+EAPI void                 e_bluez_devicefound_free(E_Bluez_Device_Found *device) EINA_ARG_NONNULL(1);
+EAPI const char *         e_bluez_devicefound_alias_get(const E_Bluez_Device_Found *device) EINA_ARG_NONNULL(1);
+
+/* Devices Methods */
+EAPI E_Bluez_Element *    e_bluez_device_get(const char *path) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_device_name_get(const E_Bluez_Element *element, const char **name) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_device_alias_get(const E_Bluez_Element *element, const char **alias) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_device_paired_get(const E_Bluez_Element *element, Eina_Bool *paired) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+/* Low-Level API:
+ *
+ * Should just be used to work around problems until proper solution
+ * is made into e_bluez.
+ */
+EAPI Eina_Bool            e_bluez_manager_sync_elements(void);
+
+EAPI Eina_Bool            e_bluez_elements_get_all(unsigned int *count, E_Bluez_Element ***p_elements) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_elements_get_all_type(const char *type, unsigned int *count, E_Bluez_Element ***p_elements) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI E_Bluez_Element *    e_bluez_element_get(const char *path);
+
+EAPI void                 e_bluez_element_listener_add(E_Bluez_Element *element, void (*cb)(void *data, const E_Bluez_Element *element), const void *data, void (*free_data)(void *data)) EINA_ARG_NONNULL(1, 2);
+EAPI void                 e_bluez_element_listener_del(E_Bluez_Element *element, void (*cb)(void *data, const E_Bluez_Element *element), const void *data) EINA_ARG_NONNULL(1, 2);
+
+EAPI int                  e_bluez_element_ref(E_Bluez_Element *element) EINA_ARG_NONNULL(1);
+EAPI int                  e_bluez_element_unref(E_Bluez_Element *element) EINA_ARG_NONNULL(1);
+
+EAPI void                 e_bluez_element_print(FILE *fp, const E_Bluez_Element *element) EINA_ARG_NONNULL(1, 2);
+EAPI void                 e_bluez_element_array_print(FILE *fp, E_Bluez_Array *array);
+
+EAPI Eina_Bool            e_bluez_element_properties_sync(E_Bluez_Element *element) EINA_ARG_NONNULL(1);
+EAPI Eina_Bool            e_bluez_element_properties_sync_full(E_Bluez_Element *element, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1);
+
+EAPI Eina_Bool            e_bluez_element_property_set(E_Bluez_Element *element, const char *prop, int type, const void *value) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_element_property_set_full(E_Bluez_Element *element, const char *prop, int type, const void *value, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_element_property_dict_set_full(E_Bluez_Element *element, const char *prop, const char *key, int type, const void *value, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+
+EAPI void                 e_bluez_element_properties_list(const E_Bluez_Element *element, Eina_Bool (*cb)(void *data, const E_Bluez_Element *element, const char *name, int type, const void *value), const void *data) EINA_ARG_NONNULL(1, 2);
+
+EAPI Eina_Bool            e_bluez_element_property_type_get_stringshared(const E_Bluez_Element *element, const char *name, int *type) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_element_property_type_get(const E_Bluez_Element *element, const char *name, int *type) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_element_property_dict_get_stringshared(const E_Bluez_Element *element, const char *dict_name, const char *key_name, int *type, void *value) EINA_ARG_NONNULL(1, 2, 4) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_element_property_get_stringshared(const E_Bluez_Element *element, const char *name, int *type, void *value) EINA_ARG_NONNULL(1, 2, 4) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_element_property_get(const E_Bluez_Element *element, const char *name, int *type, void *value) EINA_ARG_NONNULL(1, 2, 4) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool            e_bluez_element_is_adapter(const E_Bluez_Element *element) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_bluez_element_is_device(const E_Bluez_Element *element) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+
+#endif /* E_BLUEZ_H */
diff --git a/src/lib/bluez/Makefile.am b/src/lib/bluez/Makefile.am
new file mode 100644 (file)
index 0000000..8f27943
--- /dev/null
@@ -0,0 +1,24 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I $(top_srcdir)/src/lib/dbus \
+@EDBUS_CFLAGS@
+
+lib_LTLIBRARIES = libebluez.la
+includes_HEADERS = E_Bluez.h
+includesdir = $(includedir)/e_dbus-@VMAJ@
+
+libebluez_la_SOURCES = \
+e_bluez.c \
+e_bluez_element.c \
+e_bluez_manager.c \
+e_bluez_adapter.c \
+e_bluez_device.c \
+e_bluez_devicefound.c
+
+libebluez_la_LIBADD = \
+@EDBUS_LIBS@ $(top_builddir)/src/lib/dbus/libedbus.la
+
+libebluez_la_LDFLAGS = -version-info @version_info@ @release_info@
+
+EXTRA_DIST = e_bluez_private.h
diff --git a/src/lib/bluez/e_bluez.c b/src/lib/bluez/e_bluez.c
new file mode 100644 (file)
index 0000000..a49793e
--- /dev/null
@@ -0,0 +1,390 @@
+#include "e_bluez_private.h"
+#include <stdlib.h>
+#include <string.h>
+
+static E_DBus_Signal_Handler *cb_name_owner_changed = NULL;
+static DBusPendingCall *pending_get_name_owner = NULL;
+static unsigned int init_count = 0;
+static char *unique_name = NULL;
+
+static const char bus_name[] = "org.bluez";
+
+E_DBus_Connection *e_bluez_conn = NULL;
+
+EAPI int E_BLUEZ_EVENT_MANAGER_IN = 0;
+EAPI int E_BLUEZ_EVENT_MANAGER_OUT = 0;
+EAPI int E_BLUEZ_EVENT_ELEMENT_ADD = 0;
+EAPI int E_BLUEZ_EVENT_ELEMENT_DEL = 0;
+EAPI int E_BLUEZ_EVENT_ELEMENT_UPDATED = 0;
+EAPI int E_BLUEZ_EVENT_DEVICE_FOUND = 0;
+
+const char *e_bluez_iface_manager = NULL;
+const char *e_bluez_iface_adapter = NULL;
+const char *e_bluez_iface_device = NULL;
+const char *e_bluez_prop_address = NULL;
+const char *e_bluez_prop_name = NULL;
+const char *e_bluez_prop_alias = NULL;
+const char *e_bluez_prop_class = NULL;
+const char *e_bluez_prop_icon = NULL;
+const char *e_bluez_prop_paired = NULL;
+const char *e_bluez_prop_trusted = NULL;
+const char *e_bluez_prop_connected = NULL;
+const char *e_bluez_prop_uuids = NULL;
+const char *e_bluez_prop_powered = NULL;
+const char *e_bluez_prop_discoverable = NULL;
+const char *e_bluez_prop_pairable = NULL;
+const char *e_bluez_prop_discoverabletimeout = NULL;
+const char *e_bluez_prop_pairabletimeout = NULL;
+const char *e_bluez_prop_discovering = NULL;
+const char *e_bluez_prop_devices = NULL;
+
+int _e_dbus_bluez_log_dom = -1;
+
+const char *
+e_bluez_system_bus_name_get(void)
+{
+   return unique_name ? unique_name : bus_name;
+}
+
+/***********************************************************************
+* Manager
+***********************************************************************/
+
+/*
+ * FIXME: Do we really need to call Manager.GetProperties()?
+ */
+
+/**
+ * Synchronize elements with server.
+ *
+ * This will call Manager.GetProperties() on server, retrieve properties
+ * and some element paths and then request their properties.
+ *
+ * This call will add events E_BLUEZ_EVENT_ELEMENT_ADD and
+ * E_BLUEZ_EVENT_ELEMENT_UPDATED to the main loop.
+ *
+ * This will not remove stale elements.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_manager_sync_elements(void)
+{
+   E_Bluez_Element *manager;
+
+   if (!unique_name)
+      return EINA_FALSE;
+
+   manager = e_bluez_element_register(manager_path, e_bluez_iface_manager);
+   if (manager)
+      e_bluez_element_properties_sync(manager);
+   else
+      return EINA_FALSE;
+
+   DBG("sync_manager: %s (%s)", unique_name, bus_name);
+
+   return EINA_TRUE;
+}
+
+static void
+_e_bluez_system_name_owner_exit(void)
+{
+   e_bluez_manager_clear_elements();
+   ecore_event_add(E_BLUEZ_EVENT_MANAGER_OUT, NULL, NULL, NULL);
+
+   free(unique_name);
+   unique_name = NULL;
+}
+
+static void
+_e_bluez_system_name_owner_enter(const char *uid)
+{
+   DBG("enter bluez at %s (old was %s)", uid, unique_name);
+   if (unique_name && strcmp(unique_name, uid) == 0)
+     {
+        DBG("same unique_name for bluez, ignore.");
+        return;
+     }
+
+   if (unique_name)
+      _e_bluez_system_name_owner_exit();
+
+   unique_name = strdup(uid);
+
+   ecore_event_add(E_BLUEZ_EVENT_MANAGER_IN, NULL, NULL, NULL);
+   e_bluez_manager_sync_elements();
+}
+
+static void
+_e_bluez_system_name_owner_changed(void *data __UNUSED__, DBusMessage *msg)
+{
+   DBusError err;
+   const char *name, *from, *to;
+
+   dbus_error_init(&err);
+   if (!dbus_message_get_args(msg, &err,
+                              DBUS_TYPE_STRING, &name,
+                              DBUS_TYPE_STRING, &from,
+                              DBUS_TYPE_STRING, &to,
+                              DBUS_TYPE_INVALID))
+     {
+        ERR("could not get NameOwnerChanged arguments: %s: %s",
+            err.name, err.message);
+        dbus_error_free(&err);
+        return;
+     }
+
+   if (strcmp(name, bus_name) != 0)
+      return;
+
+   DBG("NameOwnerChanged from=[%s] to=[%s]", from, to);
+
+   if (from[0] == '\0' && to[0] != '\0')
+     {
+        _e_bluez_system_name_owner_enter(to);
+     }
+   else if (from[0] != '\0' && to[0] == '\0')
+     {
+        DBG("exit bluez at %s", from);
+        if (strcmp(unique_name, from) != 0)
+           DBG("%s was not the known name %s, ignored.", from, unique_name);
+        else
+           _e_bluez_system_name_owner_exit();
+     }
+   else
+     {
+        DBG("unknow change from %s to %s", from, to);
+     }
+}
+
+static void
+_e_bluez_get_name_owner(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
+{
+   DBusMessageIter itr;
+   int t;
+   const char *uid;
+
+   pending_get_name_owner = NULL;
+
+   if (!_dbus_callback_check_and_init(msg, &itr, err))
+      return;
+
+   t = dbus_message_iter_get_arg_type(&itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
+      return;
+
+   dbus_message_iter_get_basic(&itr, &uid);
+   if (!uid)
+     {
+        ERR("no name owner!");
+        return;
+     }
+
+   _e_bluez_system_name_owner_enter(uid);
+   return;
+}
+
+/**
+ * Initialize E BlueZ (E_Bluez) system.
+ *
+ * This will connect and watch org.bluez.Manager and Element
+ * events and translate to Ecore main loop events, also provide a
+ * proxy for method invocation on server.
+ *
+ * Interesting events are:
+ *   - E_BLUEZ_EVENT_MANAGER_IN: issued when bluez is avaiable.
+ *   - E_BLUEZ_EVENT_MANAGER_OUT: issued when bluez connection is lost.
+ *   - E_BLUEZ_EVENT_ELEMENT_ADD: element was added.
+ *   - E_BLUEZ_EVENT_ELEMENT_DEL: element was deleted.
+ *   - E_BLUEZ_EVENT_ELEMENT_UPDATED: element was updated (properties
+ *     or state changed).
+ *   - E_BLUEZ_EVENT_DEVICE_FOUND: a device was found, raised after calling
+ *     Adapter.StartDiscorvery()
+ *
+ * Manager IN/OUT events do not provide any event information, just
+ * tells you that system is usable or not. After manager is out, all
+ * elements will be removed, so after this event do not use the system anymore.
+ *
+ * Element events will give you an element object. After DEL event callback
+ * returns, that element will not be valid anymore.
+ */
+unsigned int
+e_bluez_system_init(E_DBus_Connection *edbus_conn)
+{
+   init_count++;
+
+   if (init_count > 1)
+      return init_count;
+
+   _e_dbus_bluez_log_dom = eina_log_domain_register
+         ("e_dbus_bluez", EINA_LOG_DEFAULT_COLOR);
+
+   if(_e_dbus_bluez_log_dom < 0)
+     {
+        EINA_LOG_ERR
+           ("impossible to create a log domain for edbus_bluez module");
+        return -1;
+     }
+
+   if (E_BLUEZ_EVENT_MANAGER_IN == 0)
+      E_BLUEZ_EVENT_MANAGER_IN = ecore_event_type_new();
+
+   if (E_BLUEZ_EVENT_MANAGER_OUT == 0)
+      E_BLUEZ_EVENT_MANAGER_OUT = ecore_event_type_new();
+
+   if (E_BLUEZ_EVENT_ELEMENT_ADD == 0)
+      E_BLUEZ_EVENT_ELEMENT_ADD = ecore_event_type_new();
+
+   if (E_BLUEZ_EVENT_ELEMENT_DEL == 0)
+      E_BLUEZ_EVENT_ELEMENT_DEL = ecore_event_type_new();
+
+   if (E_BLUEZ_EVENT_ELEMENT_UPDATED == 0)
+      E_BLUEZ_EVENT_ELEMENT_UPDATED = ecore_event_type_new();
+
+   if (E_BLUEZ_EVENT_DEVICE_FOUND == 0)
+      E_BLUEZ_EVENT_DEVICE_FOUND = ecore_event_type_new();
+
+   if (!e_bluez_iface_manager)
+      e_bluez_iface_manager = eina_stringshare_add("org.bluez.Manager");
+
+   if (!e_bluez_iface_adapter)
+      e_bluez_iface_adapter = eina_stringshare_add("org.bluez.Adapter");
+
+   if (!e_bluez_iface_device)
+      e_bluez_iface_device = eina_stringshare_add("org.bluez.Device");
+
+   if (!e_bluez_prop_address)
+      e_bluez_prop_address = eina_stringshare_add("Address");
+
+   if (!e_bluez_prop_name)
+      e_bluez_prop_name = eina_stringshare_add("Name");
+
+   if (!e_bluez_prop_alias)
+      e_bluez_prop_alias = eina_stringshare_add("Alias");
+
+   if (!e_bluez_prop_class)
+      e_bluez_prop_class = eina_stringshare_add("Class");
+
+   if (!e_bluez_prop_icon)
+      e_bluez_prop_icon = eina_stringshare_add("Icon");
+
+   if (!e_bluez_prop_paired)
+      e_bluez_prop_paired = eina_stringshare_add("Paired");
+
+   if (!e_bluez_prop_trusted)
+      e_bluez_prop_trusted = eina_stringshare_add("Trusted");
+
+   if (!e_bluez_prop_connected)
+      e_bluez_prop_connected = eina_stringshare_add("Connected");
+
+   if (!e_bluez_prop_uuids)
+      e_bluez_prop_uuids = eina_stringshare_add("UUIDs");
+
+   if (!e_bluez_prop_powered)
+      e_bluez_prop_powered = eina_stringshare_add("Powered");
+
+   if (!e_bluez_prop_discoverable)
+      e_bluez_prop_discoverable = eina_stringshare_add("Discoverable");
+
+   if (!e_bluez_prop_pairable)
+      e_bluez_prop_pairable = eina_stringshare_add("Pairable");
+
+   if (!e_bluez_prop_discoverabletimeout)
+      e_bluez_prop_discoverabletimeout = eina_stringshare_add("DiscoverableTimeout");
+
+   if (!e_bluez_prop_pairabletimeout)
+      e_bluez_prop_pairabletimeout = eina_stringshare_add("PairableTimeout");
+
+   if (!e_bluez_prop_discovering)
+      e_bluez_prop_discovering = eina_stringshare_add("Discovering");
+
+   if (!e_bluez_prop_devices)
+      e_bluez_prop_devices = eina_stringshare_add("Devices");
+
+   e_bluez_conn = edbus_conn;
+   cb_name_owner_changed = e_dbus_signal_handler_add
+         (e_bluez_conn, E_DBUS_FDO_BUS, E_DBUS_FDO_PATH, E_DBUS_FDO_INTERFACE, "NameOwnerChanged",
+         _e_bluez_system_name_owner_changed, NULL);
+
+   if (pending_get_name_owner)
+      dbus_pending_call_cancel(pending_get_name_owner);
+
+   pending_get_name_owner = e_dbus_get_name_owner
+         (e_bluez_conn, bus_name, _e_bluez_get_name_owner, NULL);
+
+   e_bluez_elements_init();
+
+   return init_count;
+}
+
+static inline void
+_stringshare_del(const char **str)
+{
+   if (!*str)
+      return;
+
+   eina_stringshare_del(*str);
+   *str = NULL;
+}
+
+/**
+ * Shutdown bluez system.
+ *
+ * When count drops to 0 resources will be released and no calls should be
+ * made anymore.
+ */
+unsigned int
+e_bluez_system_shutdown(void)
+{
+   if (init_count == 0)
+     {
+        ERR("bluez system already shut down.");
+        return 0;
+     }
+
+   init_count--;
+   if (init_count > 0)
+      return init_count;
+
+   _stringshare_del(&e_bluez_iface_manager);
+   _stringshare_del(&e_bluez_iface_adapter);
+   _stringshare_del(&e_bluez_iface_device);
+   _stringshare_del(&e_bluez_prop_address);
+   _stringshare_del(&e_bluez_prop_name);
+   _stringshare_del(&e_bluez_prop_alias);
+   _stringshare_del(&e_bluez_prop_class);
+   _stringshare_del(&e_bluez_prop_icon);
+   _stringshare_del(&e_bluez_prop_paired);
+   _stringshare_del(&e_bluez_prop_trusted);
+   _stringshare_del(&e_bluez_prop_connected);
+   _stringshare_del(&e_bluez_prop_uuids);
+   _stringshare_del(&e_bluez_prop_powered);
+   _stringshare_del(&e_bluez_prop_discoverable);
+   _stringshare_del(&e_bluez_prop_pairable);
+   _stringshare_del(&e_bluez_prop_discoverabletimeout);
+   _stringshare_del(&e_bluez_prop_pairabletimeout);
+   _stringshare_del(&e_bluez_prop_discovering);
+   _stringshare_del(&e_bluez_prop_devices);
+
+   if (pending_get_name_owner)
+     {
+        dbus_pending_call_cancel(pending_get_name_owner);
+        pending_get_name_owner = NULL;
+     }
+
+   if (cb_name_owner_changed)
+     {
+        e_dbus_signal_handler_del(e_bluez_conn, cb_name_owner_changed);
+        cb_name_owner_changed = NULL;
+     }
+
+   if (unique_name)
+      _e_bluez_system_name_owner_exit();
+
+   e_bluez_elements_shutdown();
+   eina_log_domain_unregister(_e_dbus_bluez_log_dom);
+   e_bluez_conn = NULL;
+
+   return init_count;
+}
+
diff --git a/src/lib/bluez/e_bluez_adapter.c b/src/lib/bluez/e_bluez_adapter.c
new file mode 100644 (file)
index 0000000..698cac4
--- /dev/null
@@ -0,0 +1,443 @@
+#include "e_bluez_private.h"
+
+E_Bluez_Element *
+e_bluez_adapter_get(const char *path)
+{
+   E_Bluez_Element *adapter;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+
+   adapter = e_bluez_element_get(path);
+   if (!adapter)
+      return NULL;
+
+   if (!e_bluez_element_is_adapter(adapter))
+     {
+        WRN("path '%s' is not a adapter!", path);
+        return NULL;
+     }
+
+   return adapter;
+}
+
+static void
+_device_found_callback(void *data, DBusMessage *msg)
+{
+   E_Bluez_Element *element = (E_Bluez_Element *)data;
+   E_Bluez_Device_Found *device;
+   DBusMessageIter itr;
+   int t;
+   char *name = NULL;
+   void *value = NULL;
+
+   DBG("Device found %s", element->path);
+
+   if (!_dbus_callback_check_and_init(msg, &itr, NULL))
+      return;
+
+   device = calloc(sizeof(E_Bluez_Device_Found), 1);
+   if (!device)
+     {
+        ERR("No memory to alocate E_Bluez_Device_Found");
+        return;
+     }
+
+   t = dbus_message_iter_get_arg_type(&itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
+     {
+        ERR("missing device name in DeviceFound");
+        return;
+     }
+
+   dbus_message_iter_get_basic(&itr, &name);
+
+   dbus_message_iter_next(&itr);
+   t = dbus_message_iter_get_arg_type(&itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_ARRAY))
+     {
+        ERR("missing array in DeviceFound");
+        return;
+     }
+
+   value = e_bluez_element_iter_get_array(&itr, name);
+
+   if (!value)
+      return;
+
+   device->name = eina_stringshare_add(name);
+   device->adapter = element;
+   device->array = value;
+
+   ecore_event_add(E_BLUEZ_EVENT_DEVICE_FOUND, device, NULL, NULL);
+}
+
+/**
+ * Register new agent for handling user requests.
+ *
+ * Call method RegisterAgent(object) on server in order to
+ * register new agent for handling user requests.
+ *
+ * @param element adapter's element
+ * @param object_path object to be registered.
+ * @param capability input/output agent capabilities
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_adapter_agent_register(E_Bluez_Element *element, const char *object_path, const char *capability, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "RegisterAgent";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(object_path, EINA_FALSE);
+
+   return e_bluez_element_call_with_path_and_string
+             (element, name, object_path, capability, NULL,
+             &element->_pending.agent_register, cb, data);
+}
+
+/**
+ * Unregister an existing agent.
+ *
+ * Call method UnregisterAgent(object) on server in order to
+ * unregister an existing agent.
+ *
+ * @param element adapter's element
+ * @param object_path agent to be unregistered.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_adapter_agent_unregister(E_Bluez_Element *element, const char *object_path, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "UnregisterAgent";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(object_path, EINA_FALSE);
+
+   return e_bluez_element_call_with_path
+             (element, name, object_path, NULL,
+             &element->_pending.agent_unregister, cb, data);
+}
+
+/**
+ * Get property "Address" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param address where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_adapter_address_get(const E_Bluez_Element *element, const char **address)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINA_FALSE);
+
+   return e_bluez_element_property_get_stringshared
+             (element, e_bluez_prop_address, NULL, address);
+}
+
+/**
+ * Get property "Name" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param name where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_adapter_name_get(const E_Bluez_Element *element, const char **name)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+
+   return e_bluez_element_property_get_stringshared
+             (element, e_bluez_prop_name, NULL, name);
+}
+
+/**
+ * Call method SetProperty("Name", name) at the given element on server.
+ *
+ * This is a server call, not local, so it may fail and in that case
+ * no property is updated locally. If the value was set the event
+ * E_BLUEZ_EVENT_ELEMENT_UPDATED will be added to main loop.
+ *
+ * @param name value to set.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_bluez_adapter_name_get()
+ */
+Eina_Bool
+e_bluez_adapter_name_set(E_Bluez_Element *element, const char *name, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return e_bluez_element_property_set_full
+             (element, e_bluez_prop_name, DBUS_TYPE_STRING, name, cb, data);
+}
+
+/**
+ * Get property "Powered" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param powered where to store the property value, must be a pointer
+ *        to booleans (Eina_Bool *).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_bluez_adapter_powered_set()
+ */
+Eina_Bool
+e_bluez_adapter_powered_get(const E_Bluez_Element *element, Eina_Bool *powered)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(powered, EINA_FALSE);
+
+   return e_bluez_element_property_get_stringshared
+             (element, e_bluez_prop_powered, NULL, powered);
+}
+
+/**
+ * Call method SetProperty("Powered", powered) at the given element on server.
+ *
+ *
+ * @param powered value to set.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_adapter_powered_set(E_Bluez_Element *element, Eina_Bool powered, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return e_bluez_element_property_set_full
+             (element, e_bluez_prop_powered, DBUS_TYPE_BOOLEAN,
+             &powered, cb, data);
+}
+
+/**
+ * Get property "Discoverable" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param discoverable where to store the property value, must be a pointer
+ *        to booleans (Eina_Bool *).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_bluez_adapter_discoverable_set()
+ */
+Eina_Bool
+e_bluez_adapter_discoverable_get(const E_Bluez_Element *element, Eina_Bool *discoverable)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(discoverable, EINA_FALSE);
+
+   return e_bluez_element_property_get_stringshared
+             (element, e_bluez_prop_discoverable, NULL, discoverable);
+}
+
+/**
+ * Call method SetProperty("Discoverable", discoverable) at the given
+ * element on server.
+ *
+ * @param discoverable value to set.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_adapter_discoverable_set(E_Bluez_Element *element, Eina_Bool discoverable, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return e_bluez_element_property_set_full
+             (element, e_bluez_prop_discoverable, DBUS_TYPE_BOOLEAN,
+             &discoverable, cb, data);
+}
+
+/**
+ * Get property "DiscoverableTimeout" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param adapter path to get property.
+ * @param discoverable timeout where to store the property value, must be a pointer
+ *        to uint32 (unsigned int *).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_bluez_adapter_discoverable_timeout_set()
+ */
+Eina_Bool
+e_bluez_adapter_discoverable_timeout_get(const E_Bluez_Element *element, unsigned int *timeout)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(timeout, EINA_FALSE);
+   return e_bluez_element_property_get_stringshared
+             (element, e_bluez_prop_discoverabletimeout, NULL, timeout);
+}
+
+/**
+ * Call method SetProperty("DiscoverableTimeout", timeout) at the
+ * given element on server.
+ *
+ * This is a server call, not local, so it may fail and in that case
+ * no property is updated locally. If the value was set the event
+ * E_BLUEZ_EVENT_ELEMENT_UPDATED will be added to main loop.
+ *
+ * @param adapter path to set property.
+ * @param discoverable timeout value to set.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_bluez_adapter_discoverable_timeout_get()
+ */
+Eina_Bool
+e_bluez_adapter_discoverable_timeout_set(E_Bluez_Element *element, unsigned int timeout, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return e_bluez_element_property_set_full
+             (element, e_bluez_prop_discoverabletimeout, DBUS_TYPE_UINT32,
+             &timeout, cb, data);
+}
+
+/**
+ * Get property "Discovering" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param discovering where to store the property value, must be a pointer
+ *        to booleans (Eina_Bool *).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_bluez_adapter_discovering_set()
+ */
+Eina_Bool
+e_bluez_adapter_discovering_get(const E_Bluez_Element *element, Eina_Bool *discovering)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(discovering, EINA_FALSE);
+
+   return e_bluez_element_property_get_stringshared
+             (element, e_bluez_prop_discovering, NULL, discovering);
+}
+
+/**
+ * Start Discovery of Bluetooth Devices
+ *
+ * call StartDiscovery()
+ *
+ * @param element the adapter's element.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_adapter_start_discovery(E_Bluez_Element *element, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "StartDiscovery";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+
+   element->device_found_handler =
+      e_dbus_signal_handler_add
+         (e_bluez_conn, e_bluez_system_bus_name_get(),
+         element->path, element->interface, "DeviceFound",
+         _device_found_callback, element);
+
+   return e_bluez_element_call_full
+             (element, name, NULL, &element->_pending.start_discovery, cb, data);
+}
+
+/**
+ * Stop Discovery of Bluetooth Devices
+ *
+ * call StopDiscovery()
+ *
+ * @param element the adapter's element.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_adapter_stop_discovery(E_Bluez_Element *element, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "StopDiscovery";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+
+   return e_bluez_element_call_full
+             (element, name, NULL, &element->_pending.stop_discovery, cb, data);
+}
+
+/**
+ * Create a new Paired Device.
+ *
+ * Call method CreatePairedDevice()
+ *
+ * @param element adapter's element
+ * @param object_path object to be registered.
+ * @param capability input/output agent capabilities
+ * @param device device to pair with
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_adapter_create_paired_device(E_Bluez_Element *element, const char *object_path, const char *capability, const char *device, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   DBusMessageIter itr;
+   DBusMessage *msg;
+
+   const char name[] = "CreatePairedDevice";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(object_path, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(device, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_bluez_system_bus_name_get(), element->path, element->interface,
+         name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &device);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_OBJECT_PATH, &object_path);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &capability);
+
+   return e_bluez_element_message_send
+             (element, name, NULL, msg,
+             &element->_pending.create_paired_device, cb, data);
+}
+
diff --git a/src/lib/bluez/e_bluez_device.c b/src/lib/bluez/e_bluez_device.c
new file mode 100644 (file)
index 0000000..b75c74a
--- /dev/null
@@ -0,0 +1,92 @@
+#include "e_bluez_private.h"
+
+E_Bluez_Element *
+e_bluez_device_get(const char *path)
+{
+   E_Bluez_Element *device;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+
+   device = e_bluez_element_get(path);
+   if (!device)
+      return NULL;
+
+   if (!e_bluez_element_is_device(device))
+     {
+        WRN("path '%s' is not a device!", path);
+        return NULL;
+     }
+
+   return device;
+}
+
+/**
+ * Get property "Name" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param address where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_device_name_get(const E_Bluez_Element *element, const char **name)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+
+   return e_bluez_element_property_get_stringshared
+             (element, e_bluez_prop_name, NULL, name);
+}
+
+/**
+ * Get property "Alias" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param address where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_device_alias_get(const E_Bluez_Element *element, const char **alias)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(alias, EINA_FALSE);
+
+   return e_bluez_element_property_get_stringshared
+             (element, e_bluez_prop_alias, NULL, alias);
+}
+
+/**
+ * Get property "Paired" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param powered where to store the property value, must be a pointer
+ *        to boolean (Eina_Bool *).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_device_paired_get(const E_Bluez_Element *element, Eina_Bool *paired)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(paired, EINA_FALSE);
+
+   return e_bluez_element_property_get_stringshared
+             (element, e_bluez_prop_paired, NULL, paired);
+}
+
diff --git a/src/lib/bluez/e_bluez_devicefound.c b/src/lib/bluez/e_bluez_devicefound.c
new file mode 100644 (file)
index 0000000..619bc20
--- /dev/null
@@ -0,0 +1,37 @@
+#include "e_bluez_private.h"
+
+/**
+ * Free a E_Bluez_Device_Found struct
+ *
+ * @param device the struct to be freed
+ */
+void
+e_bluez_devicefound_free(E_Bluez_Device_Found *device)
+{
+   EINA_SAFETY_ON_NULL_RETURN(device);
+
+   eina_stringshare_del(device->name);
+   e_bluez_element_array_free(device->array, NULL);
+}
+
+/**
+ * Return the pointer to the stringshared alias for the given found device.
+ *
+ * @return stringshared pointer, or @c NULL if unknown.
+ */
+const char *
+e_bluez_devicefound_alias_get(const E_Bluez_Device_Found *device)
+{
+   E_Bluez_Element_Dict_Entry *entry;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(device, NULL);
+
+   entry = e_bluez_element_array_dict_find_stringshared
+         (device->array, e_bluez_prop_alias);
+
+   if ((entry) && (entry->type == DBUS_TYPE_STRING))
+      return entry->value.str;
+
+   return NULL;
+}
+
diff --git a/src/lib/bluez/e_bluez_element.c b/src/lib/bluez/e_bluez_element.c
new file mode 100644 (file)
index 0000000..c68983f
--- /dev/null
@@ -0,0 +1,2404 @@
+#include "e_bluez_private.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+static Eina_Hash *elements = NULL;
+
+typedef struct _E_Bluez_Element_Pending     E_Bluez_Element_Pending;
+typedef struct _E_Bluez_Element_Call_Data   E_Bluez_Element_Call_Data;
+typedef struct _E_Bluez_Element_Property    E_Bluez_Element_Property;
+typedef struct _E_Bluez_Element_Listener    E_Bluez_Element_Listener;
+
+struct _E_Bluez_Element_Pending
+{
+                           EINA_INLIST;
+   DBusPendingCall        *pending;
+   void                   *data;
+   E_DBus_Method_Return_Cb user_cb;
+   void                   *user_data;
+};
+
+struct _E_Bluez_Element_Call_Data
+{
+   E_Bluez_Element         *element;
+   E_DBus_Method_Return_Cb  cb;
+   E_Bluez_Element_Pending *pending;
+   Eina_Inlist            **p_list;
+};
+
+struct _E_Bluez_Element_Property
+{
+               EINA_INLIST;
+   const char *name;
+   int         type;
+   union {
+      Eina_Bool      boolean;
+      const char    *str;
+      unsigned short u16;
+      unsigned int   u32;
+      unsigned char  byte;
+      const char    *path;
+      void          *variant;
+      E_Bluez_Array *array;
+   } value;
+};
+
+struct _E_Bluez_Element_Listener
+{
+         EINA_INLIST;
+   void  (*cb)(void *data, const E_Bluez_Element *element);
+   void *data;
+   void  (*free_data)(void *data);
+};
+
+static void
+_e_bluez_element_event_no_free(void *data __UNUSED__, void *ev)
+{
+   E_Bluez_Element *element = ev;
+   e_bluez_element_unref(element);
+}
+
+void
+e_bluez_element_event_add(int event_type, E_Bluez_Element *element)
+{
+   e_bluez_element_ref(element);
+   ecore_event_add
+      (event_type, element, _e_bluez_element_event_no_free, element);
+}
+
+static void
+e_bluez_element_call_dispatch_and_free(void *d, DBusMessage *msg, DBusError *err)
+{
+   E_Bluez_Element_Call_Data *data = d;
+   E_Bluez_Element_Pending *pending;
+
+   pending = data->pending;
+   pending->pending = NULL;
+
+   if (data->cb)
+      data->cb(data->element, msg, err);
+
+   if (pending->user_cb)
+      pending->user_cb(pending->user_data, msg, err);
+
+   pending->data = NULL;
+   *data->p_list = eina_inlist_remove(*data->p_list, EINA_INLIST_GET(pending));
+   free(pending);
+   free(data);
+}
+
+static void
+e_bluez_element_pending_cancel_and_free(Eina_Inlist **pending)
+{
+   while (*pending)
+     {
+        E_Bluez_Element_Pending *p = (E_Bluez_Element_Pending *)*pending;
+        DBusError err;
+
+        dbus_pending_call_cancel(p->pending);
+
+        dbus_error_init(&err);
+        dbus_set_error(&err, "Canceled", "Pending method call was canceled.");
+        e_bluez_element_call_dispatch_and_free(p->data, NULL, &err);
+        dbus_error_free(&err);
+     }
+}
+
+void
+e_bluez_element_listener_add(E_Bluez_Element *element, void (*cb)(void *data, const E_Bluez_Element *element), const void *data, void (*free_data)(void *data))
+{
+   E_Bluez_Element_Listener *l;
+
+   if (!element)
+     {
+        ERR("safety check failed: element == NULL");
+        goto error;
+     }
+
+   if (!cb)
+     {
+        ERR("safety check failed: cb == NULL");
+        goto error;
+     }
+
+   l = malloc(sizeof(*l));
+   if (!l)
+     {
+        ERR("could not allocate E_Bluez_Element_Listener");
+        goto error;
+     }
+
+   l->cb = cb;
+   l->data = (void *)data;
+   l->free_data = free_data;
+
+   element->_listeners = eina_inlist_append
+         (element->_listeners, EINA_INLIST_GET(l));
+
+   return;
+
+error:
+   if (free_data)
+      free_data((void *)data);
+}
+
+void
+e_bluez_element_listener_del(E_Bluez_Element *element, void (*cb)(void *data, const E_Bluez_Element *element), const void *data)
+{
+   E_Bluez_Element_Listener *l;
+
+   EINA_SAFETY_ON_NULL_RETURN(element);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+
+   EINA_INLIST_FOREACH(element->_listeners, l)
+   if ((l->cb == cb) && (l->data == data))
+     {
+        element->_listeners = eina_inlist_remove
+              (element->_listeners, EINA_INLIST_GET(l));
+        if (l->free_data)
+           l->free_data(l->data);
+
+        free(l);
+        return;
+     }
+}
+
+static void
+_e_bluez_element_listeners_call_do(E_Bluez_Element *element)
+{
+   E_Bluez_Element_Listener *l, **shadow;
+   unsigned int i, count;
+
+   /* NB: iterate on a copy in order to allow listeners to be deleted
+    * from callbacks.  number of listeners should be small, so the
+    * following should do fine.
+    */
+   count = eina_inlist_count(element->_listeners);
+   if (count < 1)
+      goto end;
+
+   shadow = alloca(sizeof(*shadow) * count);
+   if (!shadow)
+      goto end;
+
+   i = 0;
+   EINA_INLIST_FOREACH(element->_listeners, l)
+   shadow[i++] = l;
+
+   for (i = 0; i < count; i++)
+      shadow[i]->cb(shadow[i]->data, element);
+
+end:
+   e_bluez_element_event_add(E_BLUEZ_EVENT_ELEMENT_UPDATED, element);
+}
+
+static Eina_Bool
+_e_bluez_element_listeners_call_idler(void *data)
+{
+   E_Bluez_Element *element = data;
+   _e_bluez_element_listeners_call_do(element);
+   element->_idler.changed = NULL;
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_e_bluez_element_listeners_call(E_Bluez_Element *element)
+{
+   if (element->_idler.changed)
+      return;
+
+   element->_idler.changed = ecore_idler_add
+         (_e_bluez_element_listeners_call_idler, element);
+}
+
+/***********************************************************************
+* Property
+***********************************************************************/
+
+static void
+_e_bluez_element_dict_entry_free(E_Bluez_Element_Dict_Entry *entry)
+{
+   switch (entry->type)
+     {
+      case DBUS_TYPE_BOOLEAN:
+      case DBUS_TYPE_BYTE:
+      case DBUS_TYPE_INT16:
+      case DBUS_TYPE_UINT16:
+      case DBUS_TYPE_UINT32:
+         break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+         eina_stringshare_del(entry->value.path);
+         break;
+
+      case DBUS_TYPE_STRING:
+         eina_stringshare_del(entry->value.str);
+         break;
+
+      default:
+         ERR("don't know how to free dict entry '%s' of type %c (%d)",
+             entry->name, entry->type, entry->type);
+     }
+
+   eina_stringshare_del(entry->name);
+   free(entry);
+}
+
+static E_Bluez_Element_Dict_Entry *
+_e_bluez_element_dict_entry_new(DBusMessageIter *itr)
+{
+   E_Bluez_Element_Dict_Entry *entry;
+   DBusMessageIter e_itr, v_itr;
+   int t;
+   const char *key = NULL;
+   void *value = NULL;
+
+   dbus_message_iter_recurse(itr, &e_itr);
+
+   t = dbus_message_iter_get_arg_type(&e_itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
+     {
+        ERR("invalid format for dict entry. first type not a string: %c (%d)",
+            t, t);
+        return NULL;
+     }
+
+   dbus_message_iter_get_basic(&e_itr, &key);
+   if (!key || !key[0])
+     {
+        ERR("invalid format for dict entry. no key.");
+        return NULL;
+     }
+
+   dbus_message_iter_next(&e_itr);
+   t = dbus_message_iter_get_arg_type(&e_itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_VARIANT))
+     {
+        ERR("invalid format for dict entry '%s'. "
+            "second type not a variant: %c (%d)",
+            key, t, t);
+        return NULL;
+     }
+
+   dbus_message_iter_recurse(&e_itr, &v_itr);
+
+   t = dbus_message_iter_get_arg_type(&v_itr);
+   if ((t == DBUS_TYPE_INVALID) || (t == DBUS_TYPE_ARRAY))
+     {
+        ERR("invalid type for dict value for entry '%s': %c (%d)",
+            key, t, t);
+        return NULL;
+     }
+
+   entry = calloc(1, sizeof(*entry));
+   if (!entry)
+     {
+        ERR("could not allocate memory for dict entry.");
+        return NULL;
+     }
+
+   dbus_message_iter_get_basic(&v_itr, &value);
+   switch (t)
+     {
+      case DBUS_TYPE_BOOLEAN:
+         entry->value.boolean = (Eina_Bool)(long)value;
+         break;
+
+      case DBUS_TYPE_BYTE:
+         entry->value.byte = (unsigned char)(long)value;
+         break;
+
+      case DBUS_TYPE_INT16:
+         entry->value.i16 = (short)(long)value;
+         break;
+
+      case DBUS_TYPE_UINT16:
+         entry->value.u16 = (unsigned short)(long)value;
+         break;
+
+      case DBUS_TYPE_UINT32:
+         entry->value.u32 = (unsigned int)(long)value;
+         break;
+
+      case DBUS_TYPE_STRING:
+         entry->value.str = eina_stringshare_add(value);
+         break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+         entry->value.path = eina_stringshare_add(value);
+         break;
+
+      default:
+         ERR("don't know how to create dict entry '%s' for of type %c (%d)",
+             key, t, t);
+         free(entry);
+         return NULL;
+     }
+
+   entry->name = eina_stringshare_add(key);
+   entry->type = t;
+   return entry;
+}
+
+E_Bluez_Element_Dict_Entry *
+e_bluez_element_array_dict_find_stringshared(const E_Bluez_Array *array, const char *key)
+{
+   E_Bluez_Element_Dict_Entry *entry;
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+
+   EINA_ARRAY_ITER_NEXT(array->array, i, entry, iterator)
+   if (entry->name == key)
+      return entry;
+
+   return NULL;
+}
+
+void
+e_bluez_element_array_free(E_Bluez_Array *array, E_Bluez_Array *new __UNUSED__)
+{
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+   void *item;
+
+   if (!array)
+      return;
+
+   switch (array->type)
+     {
+      case DBUS_TYPE_BOOLEAN:
+      case DBUS_TYPE_BYTE:
+      case DBUS_TYPE_INT16:
+      case DBUS_TYPE_UINT16:
+      case DBUS_TYPE_UINT32:
+         break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         eina_stringshare_del(item);
+         break;
+
+      case DBUS_TYPE_STRING:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         eina_stringshare_del(item);
+         break;
+
+      case DBUS_TYPE_DICT_ENTRY:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         _e_bluez_element_dict_entry_free(item);
+         break;
+
+      default:
+         ERR("don't know how to free array of values of type %c (%d)",
+             array->type, array->type);
+         break;
+     }
+   eina_array_free(array->array);
+   free(array);
+}
+
+static void
+_e_bluez_element_property_value_free(E_Bluez_Element_Property *property)
+{
+   switch (property->type)
+     {
+      case 0:
+         return;
+
+      case DBUS_TYPE_BOOLEAN:
+      case DBUS_TYPE_BYTE:
+      case DBUS_TYPE_UINT16:
+      case DBUS_TYPE_UINT32:
+         break;
+
+      case DBUS_TYPE_STRING:
+         eina_stringshare_del(property->value.str);
+         break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+         eina_stringshare_del(property->value.path);
+         break;
+
+      case DBUS_TYPE_ARRAY:
+         e_bluez_element_array_free(property->value.array, NULL);
+         break;
+
+      default:
+         ERR("don't know how to free value of property type %c (%d)",
+             property->type, property->type);
+     }
+}
+
+static const char *
+_e_bluez_element_get_interface(const char *key)
+{
+   const char *interface = NULL, *tail;
+   char head;
+
+   head = key[0];
+   tail = key + 1;
+
+   switch (head)
+     {
+      case 'A':
+         if (strcmp(tail, "dapters") == 0)
+            interface = e_bluez_iface_adapter;
+
+         break;
+
+      case 'D':
+         if (strcmp(tail, "evices") == 0)
+            interface = e_bluez_iface_device;
+
+         break;
+
+      default:
+         break;
+     }
+
+   if (!interface)
+      ERR("failed to find interface for property \"%s\"", key);
+
+   return interface;
+}
+
+static void
+_e_bluez_element_item_register(const char *key, const char *item)
+{
+   E_Bluez_Element *element;
+   const char *interface;
+
+   interface = _e_bluez_element_get_interface(key);
+   if (!interface)
+      return;
+
+   element = e_bluez_element_register(item, interface);
+   if ((element) && (!e_bluez_element_properties_sync(element)))
+      WRN("could not get properties of %s", element->path);
+}
+
+/* Match 2 arrays to find which are new and which are old elements
+ * For new elements, register them under prop_name property
+ * For old elements, unregister them, sending proper DEL event
+ */
+static void
+_e_bluez_element_array_match(E_Bluez_Array *old, E_Bluez_Array *new, const char *prop_name)
+{
+   Eina_List *deleted = NULL;
+   Eina_Array_Iterator iter_old, iter_new;
+   unsigned int i_old = 0, i_new = 0;
+   void *item_old, *item_new;
+   Eina_List *l;
+   void *data;
+
+   if (!old)
+      return;
+
+   if (old->type != DBUS_TYPE_OBJECT_PATH)
+      return;
+
+   if ((!new) || (!new->array) || eina_array_count(new->array) == 0)
+     {
+        if ((!old) || (!old->array) || eina_array_count(old->array) == 0)
+          {
+             return;
+          }
+        else
+          {
+             iter_old = old->array->data;
+             goto out_remove_remaining;
+          }
+     }
+
+   iter_new = new->array->data;
+   item_new = *iter_new;
+   EINA_ARRAY_ITER_NEXT(old->array, i_old, item_old, iter_old)
+   {
+      if (item_old == item_new)
+        {
+           i_new++;
+           if (i_new >= eina_array_count(new->array))
+             {
+                i_old++;
+                break;
+             }
+
+           iter_new++;
+           item_new = *iter_new;
+        }
+      else
+        {
+           deleted = eina_list_append(deleted, item_old);
+        }
+   }
+
+   for(; i_new < eina_array_count(new->array); iter_new++, i_new++)
+     {
+        Eina_Bool found = EINA_FALSE;
+        item_new = *iter_new;
+        if (!item_new)
+           break;
+
+        EINA_LIST_FOREACH(deleted, l, data)
+        {
+           if (data == item_new)
+             {
+                deleted = eina_list_remove_list(deleted, l);
+                found = EINA_TRUE;
+                break;
+             }
+        }
+        if (!found)
+          {
+             _e_bluez_element_item_register(prop_name, item_new);
+             DBG("Add element %s\n", (const char *)item_new);
+          }
+     }
+
+   /* everybody after i_old on old->array + everybody from deleted list
+      will be removed
+    */
+   EINA_LIST_FREE(deleted, data)
+   {
+      E_Bluez_Element *e = e_bluez_element_get(data);
+      if (e)
+         e_bluez_element_unregister(e);
+
+      DBG("Delete element %s\n", (const char *)data);
+   }
+
+out_remove_remaining:
+   for(; i_old < eina_array_count(old->array); iter_old++, i_old++)
+     {
+        E_Bluez_Element *e;
+        item_old = *iter_old;
+        if (!item_old)
+           break;
+
+        e = e_bluez_element_get(item_old);
+        if (e)
+           e_bluez_element_unregister(e);
+
+        DBG("Delete element %s\n", (const char *)item_old);
+     }
+}
+
+static Eina_Bool
+_e_bluez_element_property_update(E_Bluez_Element_Property *property, int type, void *data)
+{
+   Eina_Bool changed = EINA_FALSE;
+
+   if ((type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) && data)
+      data = (char *)eina_stringshare_add(data);
+
+   if (property->type != type)
+     {
+        if (property->type)
+           DBG("property type changed from '%c' to '%c'",
+               property->type, type);
+
+        _e_bluez_element_property_value_free(property);
+        memset(&property->value, 0, sizeof(property->value));
+        property->type = type;
+        changed = EINA_TRUE;
+     }
+
+   switch (type)
+     {
+      case DBUS_TYPE_BOOLEAN:
+         if (changed || property->value.boolean != (Eina_Bool)(long)data)
+           {
+              property->value.boolean = (Eina_Bool)(long)data;
+              changed = EINA_TRUE;
+           }
+
+         break;
+
+      case DBUS_TYPE_BYTE:
+         if (changed || property->value.byte != (unsigned char)(long)data)
+           {
+              property->value.byte = (unsigned char)(long)data;
+              changed = EINA_TRUE;
+           }
+
+         break;
+
+      case DBUS_TYPE_UINT16:
+         if (changed || property->value.u16 != (unsigned short)(long)data)
+           {
+              property->value.u16 = (unsigned short)(long)data;
+              changed = EINA_TRUE;
+           }
+
+         break;
+
+      case DBUS_TYPE_UINT32:
+         if (changed || property->value.u32 != (unsigned int)(long)data)
+           {
+              property->value.u32 = (unsigned int)(long)data;
+              changed = EINA_TRUE;
+           }
+
+         break;
+
+      case DBUS_TYPE_STRING:
+         if (changed)
+           {
+              property->value.str = data;
+           }
+         else
+           {
+              if (property->value.str)
+                 eina_stringshare_del(property->value.str);
+
+              if (property->value.str != data)
+                {
+                   property->value.str = data;
+                   changed = EINA_TRUE;
+                }
+           }
+
+         break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+         if (changed)
+           {
+              property->value.path = data;
+           }
+         else
+           {
+              if (property->value.path)
+                 eina_stringshare_del(property->value.path);
+
+              if (property->value.path != data)
+                {
+                   property->value.path = data;
+                   changed = EINA_TRUE;
+                }
+           }
+
+         break;
+
+      case DBUS_TYPE_ARRAY:
+         if (!changed)
+            if (property->value.array)
+              {
+                 _e_bluez_element_array_match(property->value.array, data, property->name);
+                 e_bluez_element_array_free(property->value.array, data);
+              }
+
+         property->value.array = data;
+         changed = EINA_TRUE;
+         break;
+
+      default:
+         ERR("don't know how to update property type %c (%d)", type, type);
+     }
+
+   return changed;
+}
+
+static E_Bluez_Element_Property *
+_e_bluez_element_property_new(const char *name, int type, void *data)
+{
+   E_Bluez_Element_Property *property;
+
+   property = calloc(1, sizeof(*property));
+   if (!property)
+     {
+        eina_stringshare_del(name);
+        ERR("could not allocate property: %s", strerror(errno));
+        return NULL;
+     }
+
+   property->name = name;
+   _e_bluez_element_property_update(property, type, data);
+   return property;
+}
+
+static void
+_e_bluez_element_property_free(E_Bluez_Element_Property *property)
+{
+   _e_bluez_element_property_value_free(property);
+   eina_stringshare_del(property->name);
+   free(property);
+}
+
+/***********************************************************************
+* Element
+***********************************************************************/
+unsigned char *
+e_bluez_element_bytes_array_get_stringshared(const E_Bluez_Element *element, const char *property, unsigned int *count)
+{
+   Eina_Array_Iterator iterator;
+   E_Bluez_Array *array;
+   unsigned char *ret, *p;
+   unsigned int i;
+   void *item;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(property, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, NULL);
+
+   *count = 0;
+
+   if (!e_bluez_element_property_get_stringshared
+          (element, property, NULL, &array))
+      return NULL;
+
+   if ((!array) || (!(array->array)))
+      return NULL;
+
+   *count = eina_array_count(array->array);
+   ret = malloc(*count * sizeof(unsigned char));
+   if (!ret)
+     {
+        ERR("could not allocate return array of %d bytes: %s",
+            *count, strerror(errno));
+        return NULL;
+     }
+
+   p = ret;
+
+   EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+   {
+      *p = (unsigned char)(long)item;
+      p++;
+   }
+   return ret;
+}
+
+Eina_Bool
+e_bluez_element_objects_array_get_stringshared(const E_Bluez_Element *element, const char *property, unsigned int *count, E_Bluez_Element ***p_elements)
+{
+   E_Bluez_Element **ret, **p;
+   Eina_Array_Iterator iterator;
+   E_Bluez_Array *array;
+   unsigned int i;
+   int type;
+   void *item;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(property, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
+
+   *count = 0;
+   *p_elements = NULL;
+
+   if (!e_bluez_element_property_get_stringshared
+          (element, property, &type, &array))
+      return EINA_FALSE;
+
+   if (type != DBUS_TYPE_ARRAY)
+     {
+        ERR("property %s is not an array!", property);
+        return EINA_FALSE;
+     }
+
+   if ((!array) || (!array->array) || (array->type == DBUS_TYPE_INVALID))
+      return EINA_FALSE;
+
+   if (array->type != DBUS_TYPE_OBJECT_PATH)
+     {
+        ERR("property %s is not an array of object paths!", property);
+        return EINA_FALSE;
+     }
+
+   *count = eina_array_count(array->array);
+   ret = malloc(*count * sizeof(E_Bluez_Element *));
+   if (!ret)
+     {
+        ERR("could not allocate return array of %d elements: %s",
+            *count, strerror(errno));
+        *count = 0;
+        return EINA_FALSE;
+     }
+
+   p = ret;
+
+   EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+   {
+      E_Bluez_Element *e = e_bluez_element_get(item);
+      if (!e)
+         continue;
+
+      *p = e;
+      p++;
+   }
+   *count = p - ret;
+   *p_elements = ret;
+   return EINA_TRUE;
+}
+
+/* strings are just pointers (references), no strdup or stringshare_add/ref */
+Eina_Bool
+e_bluez_element_strings_array_get_stringshared(const E_Bluez_Element *element, const char *property, unsigned int *count, const char ***strings)
+{
+   const char **ret, **p;
+   Eina_Array_Iterator iterator;
+   E_Bluez_Array *array;
+   unsigned int i;
+   int type;
+   void *item;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(property, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(strings, EINA_FALSE);
+
+   *count = 0;
+   *strings = NULL;
+
+   if (!e_bluez_element_property_get_stringshared
+          (element, property, &type, &array))
+      return EINA_FALSE;
+
+   if (type != DBUS_TYPE_ARRAY)
+     {
+        ERR("property %s is not an array!", property);
+        return EINA_FALSE;
+     }
+
+   if ((!array) || (!array->array) || (array->type == DBUS_TYPE_INVALID))
+      return EINA_FALSE;
+
+   if (array->type != DBUS_TYPE_STRING)
+     {
+        ERR("property %s is not an array of strings!", property);
+        return EINA_FALSE;
+     }
+
+   *count = eina_array_count(array->array);
+   ret = malloc(*count * sizeof(char *));
+   if (!ret)
+     {
+        ERR("could not allocate return array of %d strings: %s",
+            *count, strerror(errno));
+        *count = 0;
+        return EINA_FALSE;
+     }
+
+   p = ret;
+
+   EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+   {
+      if (!item)
+         continue;
+
+      *p = item;
+      p++;
+   }
+   *count = p - ret;
+   *strings = ret;
+   return EINA_TRUE;
+}
+
+void
+e_bluez_element_array_print(FILE *fp, E_Bluez_Array *array)
+{
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+   void *item;
+
+   if (!array)
+      return;
+
+   switch (array->type)
+     {
+      case DBUS_TYPE_OBJECT_PATH:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "\"%s\", ", (const char *)item);
+         break;
+
+      case DBUS_TYPE_STRING:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "\"%s\", ", (const char *)item);
+         break;
+
+      case DBUS_TYPE_BYTE:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "%#02hhx (\"%c\"), ", (unsigned char)(long)item,
+                 (unsigned char)(long)item);
+         break;
+
+      case DBUS_TYPE_UINT16:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "%#04hx (%hu), ", (unsigned short)(long)item,
+                 (unsigned short)(long)item);
+         break;
+
+      case DBUS_TYPE_UINT32:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "%#08x (%u), ", (unsigned int)(long)item,
+                 (unsigned int)(long)item);
+         break;
+
+      case DBUS_TYPE_DICT_ENTRY:
+         fputs("{ ", fp);
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         {
+            E_Bluez_Element_Dict_Entry *entry = item;
+            fprintf(fp, "%s: ", entry->name);
+            switch (entry->type)
+              {
+               case DBUS_TYPE_OBJECT_PATH:
+                  fprintf(fp, "\"%s\", ", entry->value.path);
+                  break;
+
+               case DBUS_TYPE_STRING:
+                  fprintf(fp, "\"%s\", ", entry->value.str);
+                  break;
+
+               case DBUS_TYPE_BOOLEAN:
+                  fprintf(fp, "%hhu, ",
+                          entry->value.boolean);
+                  break;
+
+               case DBUS_TYPE_BYTE:
+                  fprintf(fp, "%#02hhx (\"%c\"), ",
+                          entry->value.byte, entry->value.byte);
+                  break;
+
+               case DBUS_TYPE_INT16:
+                  fprintf(fp, "%#04hx (%hi), ",
+                          entry->value.i16, entry->value.i16);
+                  break;
+
+               case DBUS_TYPE_UINT16:
+                  fprintf(fp, "%#04hx (%hu), ",
+                          entry->value.u16, entry->value.u16);
+                  break;
+
+               case DBUS_TYPE_UINT32:
+                  fprintf(fp, "%#08x (%u), ",
+                          entry->value.u32, entry->value.u32);
+                  break;
+
+               default:
+                  fprintf(fp, "<UNKNOWN TYPE '%c'>", entry->type);
+              }
+         }
+         fputs("}", fp);
+         break;
+
+      default:
+         fprintf(fp, "<UNKNOWN ARRAY TYPE '%c'>", array->type);
+     }
+}
+
+/**
+ * Print element to file descriptor.
+ */
+void
+e_bluez_element_print(FILE *fp, const E_Bluez_Element *element)
+{
+   const E_Bluez_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN(fp);
+   if (!element)
+     {
+        fputs("Error: no element to print\n", fp);
+        return;
+     }
+
+   fprintf(fp,
+           "Element %p: %s [%s]\n"
+           "\tProperties:\n",
+           element, element->path, element->interface);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      fprintf(fp, "\t\t%s (%c) = ", p->name, p->type);
+
+      switch (p->type)
+        {
+         case DBUS_TYPE_STRING:
+            fprintf(fp, "\"%s\"", p->value.str);
+            break;
+
+         case DBUS_TYPE_OBJECT_PATH:
+            fprintf(fp, "\"%s\"", p->value.path);
+            break;
+
+         case DBUS_TYPE_BOOLEAN:
+            fprintf(fp, "%hhu", p->value.boolean);
+            break;
+
+         case DBUS_TYPE_BYTE:
+            fprintf(fp, "%#02hhx (%d), ", p->value.byte, p->value.byte);
+            break;
+
+         case DBUS_TYPE_UINT16:
+            fprintf(fp, "%hu", p->value.u16);
+            break;
+
+         case DBUS_TYPE_UINT32:
+            fprintf(fp, "%u", p->value.u32);
+            break;
+
+         case DBUS_TYPE_ARRAY:
+            e_bluez_element_array_print(fp, p->value.array);
+            break;
+
+         default:
+            fputs("don't know how to print type", fp);
+        }
+
+      fputc('\n', fp);
+   }
+}
+
+static E_Bluez_Element *
+e_bluez_element_new(const char *path, const char *interface)
+{
+   E_Bluez_Element *element;
+
+   element = calloc(1, sizeof(*element));
+   if (!element)
+     {
+        ERR("could not allocate element: %s",   strerror(errno));
+        return NULL;
+     }
+
+   element->path = eina_stringshare_add(path);
+   element->interface = eina_stringshare_ref(interface);
+   element->_references = 1;
+
+   return element;
+}
+
+static void
+e_bluez_element_extra_properties_free(E_Bluez_Element *element)
+{
+   while (element->props)
+     {
+        E_Bluez_Element_Property *prop;
+        prop = (E_Bluez_Element_Property *)element->props;
+        element->props = element->props->next;
+        _e_bluez_element_property_free(prop);
+     }
+}
+
+static void
+e_bluez_element_free(E_Bluez_Element *element)
+{
+   if (element->_idler.changed)
+      ecore_idler_del(element->_idler.changed);
+
+   while (element->_listeners)
+     {
+        E_Bluez_Element_Listener *l = (void *)element->_listeners;
+        element->_listeners = eina_inlist_remove
+              (element->_listeners, element->_listeners);
+
+        if (l->free_data)
+           l->free_data(l->data);
+
+        free(l);
+     }
+
+   e_bluez_element_pending_cancel_and_free(&element->_pending.properties_get);
+   e_bluez_element_pending_cancel_and_free(&element->_pending.property_set);
+   e_bluez_element_pending_cancel_and_free(&element->_pending.agent_register);
+   e_bluez_element_pending_cancel_and_free(&element->_pending.agent_unregister);
+
+   e_bluez_element_extra_properties_free(element);
+   eina_stringshare_del(element->interface);
+   eina_stringshare_del(element->path);
+   free(element);
+}
+
+/**
+ * Add reference to element.
+ */
+int
+e_bluez_element_ref(E_Bluez_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, 0);
+   return ++element->_references;
+}
+
+/**
+ * Remove reference from element.
+ *
+ * If reference count drops to 0 element will be freed.
+ */
+int
+e_bluez_element_unref(E_Bluez_Element *element)
+{
+   int i;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, 0);
+
+   i = --element->_references;
+   if (i == 0)
+      e_bluez_element_free(element);
+   else if (i < 0)
+      ERR("element %p references %d < 0", element, i);
+
+   return i;
+}
+
+/**
+ * Send message with callbacks set to work with bluez elements.
+ *
+ * If this call fails (returns @c EINA_FALSE), pending callbacks will not be called,
+ * not even with error messages.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
+ */
+Eina_Bool
+e_bluez_element_message_send(E_Bluez_Element *element, const char *method_name, E_DBus_Method_Return_Cb cb, DBusMessage *msg, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
+{
+   E_Bluez_Element_Call_Data *data;
+   E_Bluez_Element_Pending *p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(msg, EINA_FALSE);
+
+   data = malloc(sizeof(*data));
+   if (!data)
+     {
+        ERR("could not alloc e_bluez_element_call_data: %s",
+            strerror(errno));
+        dbus_message_unref(msg);
+        return EINA_FALSE;
+     }
+
+   p = malloc(sizeof(*p));
+   if (!p)
+     {
+        ERR("could not alloc E_Bluez_Element_Pending: %s",
+            strerror(errno));
+        free(data);
+        dbus_message_unref(msg);
+        return EINA_FALSE;
+     }
+
+   data->element = element;
+   data->cb = cb;
+   data->pending = p;
+   data->p_list = pending;
+   p->user_cb = user_cb;
+   p->user_data = (void *)user_data;
+   p->data = data;
+   p->pending = e_dbus_message_send
+         (e_bluez_conn, msg, e_bluez_element_call_dispatch_and_free, -1, data);
+   dbus_message_unref(msg);
+
+   if (p->pending)
+     {
+        *pending = eina_inlist_append(*pending, EINA_INLIST_GET(p));
+        return EINA_TRUE;
+     }
+
+   ERR("failed to call %s (obj=%s, path=%s, iface=%s)",
+       method_name, e_bluez_system_bus_name_get(),
+       element->path, element->interface);
+   free(data);
+   free(p);
+   return EINA_FALSE;
+}
+
+Eina_Bool
+e_bluez_element_call_full(E_Bluez_Element *element, const char *method_name, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
+{
+   DBusMessage *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_bluez_system_bus_name_get(), element->path, element->interface,
+         method_name);
+
+   return e_bluez_element_message_send
+             (element, method_name, cb, msg, pending, user_cb, user_data);
+}
+
+static Eina_Bool
+_e_bluez_element_property_value_add(E_Bluez_Element *element, const char *name, int type, void *value)
+{
+   E_Bluez_Element_Property *p;
+
+   name = eina_stringshare_add(name);
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      if (p->name == name)
+        {
+           eina_stringshare_del(name);
+           return _e_bluez_element_property_update(p, type, value);
+        }
+   }
+
+   p = _e_bluez_element_property_new(name, type, value);
+   if (!p)
+     {
+        ERR("could not create property %s (%c)", name, type);
+        return EINA_FALSE;
+     }
+
+   element->props = eina_inlist_append(element->props, EINA_INLIST_GET(p));
+   return EINA_TRUE;
+}
+
+E_Bluez_Array *
+e_bluez_element_iter_get_array(DBusMessageIter *itr, const char *key)
+{
+   E_Bluez_Array *array;
+   DBusMessageIter e_itr;
+
+   array = malloc(sizeof(E_Bluez_Array));
+   if (!array)
+     {
+        ERR("could not create new e_bluez array.");
+        return NULL;
+     }
+
+   array->array = eina_array_new(16);
+   if (!(array->array))
+     {
+        ERR("could not create new eina array.");
+        free(array);
+        return NULL;
+     }
+
+   dbus_message_iter_recurse(itr, &e_itr);
+   array->type = dbus_message_iter_get_arg_type(&e_itr);
+   if (array->type == DBUS_TYPE_INVALID)
+     {
+        DBG("array %s is of type 'invalid' (empty?)", key);
+        eina_array_free(array->array);
+        free(array);
+        return NULL;
+     }
+
+   do
+     {
+        switch (array->type)
+          {
+           case DBUS_TYPE_OBJECT_PATH:
+           {
+              const char *path;
+
+              dbus_message_iter_get_basic(&e_itr, &path);
+              path = eina_stringshare_add(path);
+              eina_array_push(array->array, path);
+              _e_bluez_element_item_register(key, path);
+           }
+           break;
+
+           case DBUS_TYPE_STRING:
+           {
+              const char *str;
+
+              dbus_message_iter_get_basic(&e_itr, &str);
+              str = eina_stringshare_add(str);
+              eina_array_push(array->array, str);
+           }
+           break;
+
+           case DBUS_TYPE_BYTE:
+           {
+              unsigned char byte;
+              dbus_message_iter_get_basic(&e_itr, &byte);
+              eina_array_push(array->array, (void *)(long)byte);
+           }
+           break;
+
+           case DBUS_TYPE_DICT_ENTRY:
+           {
+              E_Bluez_Element_Dict_Entry *entry;
+              entry = _e_bluez_element_dict_entry_new(&e_itr);
+              if (entry)
+                 eina_array_push(array->array, entry);
+           }
+           break;
+
+           default:
+              ERR("don't know how to build array '%s' of type %c (%d)",
+                  key, array->type, array->type);
+              eina_array_free(array->array);
+              free(array);
+              return NULL;
+          }
+     }
+   while (dbus_message_iter_next(&e_itr));
+   return array;
+}
+
+static void
+_e_bluez_element_get_properties_callback(void *user_data, DBusMessage *msg, DBusError *err)
+{
+   E_Bluez_Element *element = user_data;
+   DBusMessageIter itr, s_itr;
+   int t, changed;
+
+   DBG("get_properties msg=%p", msg);
+
+   if (!_dbus_callback_check_and_init(msg, &itr, err))
+      return;
+
+   t = dbus_message_iter_get_arg_type(&itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_ARRAY))
+      return;
+
+   changed = 0;
+   dbus_message_iter_recurse(&itr, &s_itr);
+   do
+     {
+        DBusMessageIter e_itr, v_itr;
+        const char *key;
+        void *value = NULL;
+        int r;
+
+        t = dbus_message_iter_get_arg_type(&s_itr);
+        if (!_dbus_iter_type_check(t, DBUS_TYPE_DICT_ENTRY))
+           continue;
+
+        dbus_message_iter_recurse(&s_itr, &e_itr);
+
+        t = dbus_message_iter_get_arg_type(&e_itr);
+        if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
+           continue;
+
+        dbus_message_iter_get_basic(&e_itr, &key);
+        dbus_message_iter_next(&e_itr);
+        t = dbus_message_iter_get_arg_type(&e_itr);
+        if (!_dbus_iter_type_check(t, DBUS_TYPE_VARIANT))
+           continue;
+
+        dbus_message_iter_recurse(&e_itr, &v_itr);
+        t = dbus_message_iter_get_arg_type(&v_itr);
+        if (t == DBUS_TYPE_ARRAY)
+          {
+             value = e_bluez_element_iter_get_array(&v_itr, key);
+          }
+        else if (t != DBUS_TYPE_INVALID)
+          {
+             dbus_message_iter_get_basic(&v_itr, &value);
+          }
+        else
+          {
+             ERR("property has invalid type %s", key);
+             continue;
+          }
+
+        r = _e_bluez_element_property_value_add(element, key, t, value);
+        if (r < 0)
+          {
+             ERR("failed to add property value %s (%c)", key, t);
+          }
+        else if (r == 1)
+          {
+             INF("property value changed %s (%c)", key, t);
+             changed = 1;
+          }
+     }
+   while (dbus_message_iter_next(&s_itr));
+
+   if (changed)
+      _e_bluez_element_listeners_call(element);
+}
+
+/**
+ * Sync element properties with server.
+ *
+ * Call method GetProperties() at the given element on server in order to sync
+ * them.
+ *
+ * @param element to call method on server.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_element_properties_sync_full(E_Bluez_Element *element, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "GetProperties";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return e_bluez_element_call_full
+             (element, name, _e_bluez_element_get_properties_callback,
+             &element->_pending.properties_get, cb, data);
+}
+
+/**
+ * Sync element properties with server, simple version.
+ *
+ * Call method GetProperties() at the given element on server in order to sync
+ * them. This is the simple version and there is no check of server reply
+ * for errors.
+ *
+ * @param element to call method on server.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_element_properties_sync(E_Bluez_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return e_bluez_element_properties_sync_full(element, NULL, NULL);
+}
+
+/**
+ * Call method SetProperty(prop, {key: value}) at the given element on server.
+ *
+ * This is a server call, not local, so it may fail and in that case
+ * no property is updated locally. If the value was set the event
+ * E_BLUEZ_EVENT_ELEMENT_UPDATED will be added to main loop.
+ *
+ * @param element to call method on server.
+ * @param prop property name.
+ * @param key dict key name.
+ * @param type DBus type to use for value.
+ * @param value pointer to value, just like regular DBus, see
+ *        dbus_message_iter_append_basic().
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_element_property_dict_set_full(E_Bluez_Element *element, const char *prop, const char *key, int type, const void *value, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "SetProperty";
+   DBusMessage *msg;
+   DBusMessageIter itr, variant, dict, entry;
+   char typestr[32];
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_bluez_system_bus_name_get(), element->path, element->interface, name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &prop);
+
+   if ((size_t)snprintf(typestr, sizeof(typestr),
+                        (DBUS_TYPE_ARRAY_AS_STRING
+                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                         DBUS_TYPE_STRING_AS_STRING
+                         "%c"
+                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
+                        type) >= sizeof(typestr))
+     {
+        ERR("sizeof(typestr) is too small!");
+        return EINA_FALSE;
+     }
+
+   if (dbus_message_iter_open_container(&itr, DBUS_TYPE_VARIANT, typestr, &variant))
+     {
+        snprintf(typestr, sizeof(typestr),
+                 (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                     DBUS_TYPE_STRING_AS_STRING
+                     "%c"
+                     DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
+                 type);
+        
+        if (dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, typestr, &dict))
+          {
+             if (dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry))
+               {
+                  dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+                  if ((type == DBUS_TYPE_STRING) || (type == DBUS_TYPE_OBJECT_PATH))
+                    dbus_message_iter_append_basic(&entry, type, &value);
+                  else
+                    dbus_message_iter_append_basic(&entry, type, value);
+                  
+                  dbus_message_iter_close_container(&dict, &entry);
+               }
+             else
+               {
+                  ERR("dbus_message_iter_open_container() failed");
+               }
+             dbus_message_iter_close_container(&variant, &dict);
+          }
+        else
+          {
+             ERR("dbus_message_iter_open_container() failed");
+          }
+        dbus_message_iter_close_container(&itr, &variant);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+
+   return e_bluez_element_message_send
+             (element, name, NULL, msg, &element->_pending.property_set, cb, data);
+}
+
+/**
+ * Call method SetProperty(prop, value) at the given element on server.
+ *
+ * This is a server call, not local, so it may fail and in that case
+ * no property is updated locally. If the value was set the event
+ * E_BLUEZ_EVENT_ELEMENT_UPDATED will be added to main loop.
+ *
+ * @param element to call method on server.
+ * @param prop property name.
+ * @param type DBus type to use for value.
+ * @param value pointer to value, just like regular DBus, see
+ *        dbus_message_iter_append_basic().
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_element_property_set_full(E_Bluez_Element *element, const char *prop, int type, const void *value, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "SetProperty";
+   char typestr[2];
+   DBusMessage *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_bluez_system_bus_name_get(), element->path, element->interface, name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   DBusMessageIter itr, v;
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &prop);
+
+   typestr[0] = type;
+   typestr[1] = '\0';
+   if (dbus_message_iter_open_container(&itr, DBUS_TYPE_VARIANT, typestr, &v))
+     {
+        if ((type == DBUS_TYPE_STRING) || (type == DBUS_TYPE_OBJECT_PATH))
+          {
+             dbus_message_iter_append_basic(&v, type, &value);
+          }
+        else if (type == DBUS_TYPE_BOOLEAN)
+          {
+             unsigned int b = *(char *)value;
+             dbus_message_iter_append_basic(&v, type, &b);
+          }
+        else
+          {
+             dbus_message_iter_append_basic(&v, type, value);
+          }
+        dbus_message_iter_close_container(&itr, &v);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+   
+   return e_bluez_element_message_send
+             (element, name, NULL, msg, &element->_pending.property_set, cb, data);
+}
+
+/**
+ * Call method SetProperty(prop, value) at the given element on server.
+ *
+ * This is the simple version and there is no check of server reply
+ * for errors.
+ *
+ * @param element to call method on server.
+ * @param prop property name.
+ * @param type DBus type to use for value.
+ * @param value pointer to value, just like regular DBus, see
+ *        dbus_message_iter_append_basic().
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_element_property_set(E_Bluez_Element *element, const char *prop, int type, const void *value)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
+   return e_bluez_element_property_set_full
+             (element, prop, type, value, NULL, NULL);
+}
+
+Eina_Bool
+e_bluez_element_call_with_path(E_Bluez_Element *element, const char *method_name, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
+{
+   DBusMessageIter itr;
+   DBusMessage *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_bluez_system_bus_name_get(), element->path, element->interface,
+         method_name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_OBJECT_PATH, &string);
+
+   return e_bluez_element_message_send
+             (element, method_name, cb, msg, pending, user_cb, user_data);
+}
+
+Eina_Bool
+e_bluez_element_call_with_string(E_Bluez_Element *element, const char *method_name, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
+{
+   DBusMessageIter itr;
+   DBusMessage *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_bluez_system_bus_name_get(), element->path, element->interface,
+         method_name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &string);
+
+   return e_bluez_element_message_send
+             (element, method_name, cb, msg, pending, user_cb, user_data);
+}
+
+Eina_Bool
+e_bluez_element_call_with_path_and_string(E_Bluez_Element *element, const char *method_name, const char *path, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
+{
+   DBusMessageIter itr;
+   DBusMessage *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_bluez_system_bus_name_get(), element->path, element->interface,
+         method_name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_OBJECT_PATH, &path);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &string);
+
+   return e_bluez_element_message_send
+             (element, method_name, cb, msg, pending, user_cb, user_data);
+}
+
+/**
+ * Get property type.
+ *
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param name property name, must be previously stringshared
+ * @param type will contain the value type.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_element_property_type_get_stringshared(const E_Bluez_Element *element, const char *name, int *type)
+{
+   const E_Bluez_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      if (p->name == name)
+        {
+           *type = p->type;
+           return EINA_TRUE;
+        }
+   }
+
+   WRN("element %s (%p) has no property with name \"%s\".",
+       element->path, element, name);
+   return EINA_FALSE;
+}
+
+/**
+ * Get property type.
+ *
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param name property name
+ * @param type will contain the value type.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_element_property_type_get(const E_Bluez_Element *element, const char *name, int *type)
+{
+   Eina_Bool ret;
+   name = eina_stringshare_add(name);
+   ret = e_bluez_element_property_type_get_stringshared(element, name, type);
+   eina_stringshare_del(name);
+   return ret;
+}
+
+void
+e_bluez_element_list_properties(const E_Bluez_Element *element, Eina_Bool (*cb)(void *data, const E_Bluez_Element *element, const char *name, int type, const void *value), const void *data)
+{
+   const E_Bluez_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN(element);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      const void *value = NULL;
+
+      switch (p->type)
+        {
+         case DBUS_TYPE_STRING:
+            value = &p->value.str;
+            break;
+
+         case DBUS_TYPE_OBJECT_PATH:
+            value = &p->value.path;
+            break;
+
+         case DBUS_TYPE_BOOLEAN:
+            value = (void *)(unsigned long)p->value.boolean;
+            break;
+
+         case DBUS_TYPE_UINT16:
+            value = &p->value.u16;
+            break;
+
+         case DBUS_TYPE_UINT32:
+            value = &p->value.u32;
+            break;
+
+         default:
+            ERR("unsupported type %c", p->type);
+        }
+
+      if (!cb((void *)data, element, p->name, p->type, value))
+         return;
+   }
+}
+
+/**
+ * Get dict value given its key inside a dict property.
+ *
+ * This will look into properties for one of type dict that contains
+ * the given key, to find the property.  If no property is found then
+ * @c EINA_FALSE is returned.
+ *
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param dict_name property name, must be previously stringshared
+ * @param key key inside dict, must be previously stringshared
+ * @param type if provided it will contain the value type.
+ * @param value where to store the property value, must be a pointer to the
+ *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_element_property_dict_get_stringshared(const E_Bluez_Element *element, const char *dict_name, const char *key, int *type, void *value)
+{
+   const E_Bluez_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dict_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      E_Bluez_Element_Dict_Entry *entry;
+      E_Bluez_Array *array;
+
+      if (p->name != dict_name)
+         continue;
+
+      if (p->type != DBUS_TYPE_ARRAY)
+        {
+           WRN("element %s (%p) has property \"%s\" is not an array: %c (%d)",
+               element->path, element, dict_name, p->type, p->type);
+           return EINA_FALSE;
+        }
+
+      array = p->value.array;
+      if ((!array) || (array->type != DBUS_TYPE_DICT_ENTRY))
+        {
+           int t = array ? array->type : DBUS_TYPE_INVALID;
+           WRN("element %s (%p) has property \"%s\" is not a dict: %c (%d)",
+               element->path, element, dict_name, t, t);
+           return EINA_FALSE;
+        }
+
+      entry = e_bluez_element_array_dict_find_stringshared(array, key);
+      if (!entry)
+        {
+           WRN("element %s (%p) has no dict property with name \"%s\" with "
+               "key \"%s\".",
+               element->path, element, dict_name, key);
+           return EINA_FALSE;
+        }
+
+      if (type)
+         *type = entry->type;
+
+      switch (entry->type)
+        {
+         case DBUS_TYPE_BOOLEAN:
+            *(Eina_Bool *)value = entry->value.boolean;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_BYTE:
+            *(unsigned char *)value = entry->value.byte;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_INT16:
+            *(short *)value = entry->value.i16;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_UINT16:
+            *(unsigned short *)value = entry->value.u16;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_UINT32:
+            *(unsigned int *)value = entry->value.u32;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_STRING:
+            *(const char **)value = entry->value.str;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_OBJECT_PATH:
+            *(const char **)value = entry->value.path;
+            return EINA_TRUE;
+
+         default:
+            ERR("don't know how to get property %s, key %s type %c (%d)",
+                dict_name, key, entry->type, entry->type);
+            return EINA_FALSE;
+        }
+   }
+
+   WRN("element %s (%p) has no property with name \"%s\".",
+       element->path, element, dict_name);
+   return EINA_FALSE;
+}
+
+/**
+ * Get property value given its name.
+ *
+ * This will look into properties, to find the property.
+ * If no property is found then @c EINA_FALSE is returned.
+ *
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param name property name, must be previously stringshared
+ * @param type if provided it will contain the value type.
+ * @param value where to store the property value, must be a pointer to the
+ *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_element_property_get_stringshared(const E_Bluez_Element *element, const char *name, int *type, void *value)
+{
+   const E_Bluez_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      if (p->name != name)
+         continue;
+
+      if (type)
+         *type = p->type;
+
+      switch (p->type)
+        {
+         case DBUS_TYPE_BOOLEAN:
+            *(Eina_Bool *)value = p->value.boolean;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_BYTE:
+            *(unsigned char *)value = p->value.byte;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_UINT16:
+            *(unsigned short *)value = p->value.u16;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_UINT32:
+            *(unsigned int *)value = p->value.u32;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_STRING:
+            *(const char **)value = p->value.str;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_OBJECT_PATH:
+            *(const char **)value = p->value.path;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_ARRAY:
+            *(E_Bluez_Array **)value = p->value.array;
+            return EINA_TRUE;
+
+         default:
+            ERR("don't know how to get property type %c (%d)",
+                p->type, p->type);
+            return EINA_FALSE;
+        }
+   }
+
+   WRN("element %s (%p) has no property with name \"%s\".",
+       element->path, element, name);
+   return EINA_FALSE;
+}
+
+/**
+ * Get property value given its name.
+ *
+ * This will look into properties, to find the property.
+ * If no property is found then @c EINA_FALSE is returned.
+ *
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param name property name
+ * @param type if provided it will contain the value type.
+ * @param value where to store the property value, must be a pointer to the
+ *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_element_property_get(const E_Bluez_Element *element, const char *name, int *type, void *value)
+{
+   Eina_Bool ret;
+   name = eina_stringshare_add(name);
+   ret = e_bluez_element_property_get_stringshared
+         (element, name, type, value);
+   eina_stringshare_del(name);
+   return ret;
+}
+
+struct e_bluez_elements_for_each_data
+{
+   Eina_Hash_Foreach cb;
+   void             *data;
+};
+
+static Eina_Bool
+_e_bluez_elements_for_each(Eina_Hash *hash __UNUSED__, const char *key, void *data, void *fdata)
+{
+   struct e_bluez_elements_for_each_data *each_data = fdata;
+
+   each_data->cb(elements, key, data, each_data->data);
+   return EINA_TRUE;
+}
+
+/**
+ * Call the given function for each existing element.
+ *
+ * @param cb function to call for each element. It will get as parameters,
+ *        in order: the element pointer and the given @a user_data.
+ * @param user_data data to give to @a cb for each element.
+ */
+void
+e_bluez_elements_for_each(Eina_Hash_Foreach cb, const void *user_data)
+{
+   struct e_bluez_elements_for_each_data data = {cb, (void *)user_data};
+
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+
+   eina_hash_foreach(elements, (Eina_Hash_Foreach)_e_bluez_elements_for_each,
+                     &data);
+}
+
+static Eina_Bool
+_e_bluez_elements_get_allocate(unsigned int *count, E_Bluez_Element ***p_elements)
+{
+   *count = eina_hash_population(elements);
+   if (*count == 0)
+     {
+        *p_elements = NULL;
+        return EINA_TRUE;
+     }
+
+   *p_elements = malloc(*count * sizeof(E_Bluez_Element *));
+   if (!*p_elements)
+     {
+        ERR("could not allocate return array of %d elements: %s",
+            *count, strerror(errno));
+        *count = 0;
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_bluez_elements_get_all(Eina_Hash *hash __UNUSED__, const char *key __UNUSED__, void *data, void *fdata)
+{
+   E_Bluez_Element *element = data;
+   E_Bluez_Element ***p_ret = fdata;
+
+   **p_ret = element;
+   (*p_ret)++;
+   return EINA_TRUE;
+}
+
+/**
+ * Get all known elements.
+ *
+ * No reference is added to these elements, since there are no threads
+ * in the system, you are free to add references yourself right after
+ * the return of this call without race condition, elements by the
+ * system (ie: elementRemoved signal)could only be touched on the next
+ * main loop iteration.
+ *
+ * @param count return the number of elements in array.
+ * @param p_elements array with all elements, these are not referenced
+ *        and in no particular order, just set if return is 1.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_elements_get_all(unsigned int *count, E_Bluez_Element ***p_elements)
+{
+   E_Bluez_Element **p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
+
+   if (!_e_bluez_elements_get_allocate(count, p_elements))
+      return EINA_FALSE;
+
+   p = *p_elements;
+   eina_hash_foreach(elements, (Eina_Hash_Foreach)_e_bluez_elements_get_all,
+                     &p);
+   return EINA_TRUE;
+}
+
+struct e_bluez_elements_get_all_str_data
+{
+   E_Bluez_Element **elements;
+   int               count;
+   const char       *str;
+};
+
+static Eina_Bool
+_e_bluez_elements_get_all_type(Eina_Hash *hash __UNUSED__, const char *key __UNUSED__, void *e, void *user_data)
+{
+   struct e_bluez_elements_get_all_str_data *data = user_data;
+   E_Bluez_Element *element = e;
+
+   if ((data->str) && (element->interface != data->str))
+      return EINA_TRUE;
+
+   data->elements[data->count] = element;
+   data->count++;
+   return EINA_TRUE;
+}
+
+/**
+ * Get all known elements of type.
+ *
+ * No reference is added to these elements, since there are no threads
+ * in the system, you are free to add references yourself right after
+ * the return of this call without race condition, elements by the
+ * system (ie: ElementRemoved signal) could only be touched on the next
+ * main loop iteration.
+ *
+ * @param type type to filter, or NULL to get all.
+ * @param count return the number of elements in array.
+ * @param p_elements array with all elements, these are not referenced
+ *        and in no particular order, just set if return is 1.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * @see e_bluez_elements_get_all()
+ */
+Eina_Bool
+e_bluez_elements_get_all_type(const char *type, unsigned int *count, E_Bluez_Element ***p_elements)
+{
+   struct e_bluez_elements_get_all_str_data data;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
+
+   if (!_e_bluez_elements_get_allocate(count, p_elements))
+      return EINA_FALSE;
+
+   data.elements = *p_elements;
+   data.count = 0;
+   data.str = eina_stringshare_add(type);
+   eina_hash_foreach(elements,
+                     (Eina_Hash_Foreach)_e_bluez_elements_get_all_type,
+                     &data);
+
+   eina_stringshare_del(data.str);
+   *count = data.count;
+   return EINA_TRUE;
+}
+
+/**
+ * Get the element registered at given path.
+ *
+ * @param path the path to query for registered object.
+ *
+ * @return element pointer if found, NULL otherwise. No references are added.
+ */
+E_Bluez_Element *
+e_bluez_element_get(const char *path)
+{
+   E_Bluez_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+   element = eina_hash_find(elements, path);
+
+   return element;
+}
+
+static void
+_e_bluez_element_property_changed_callback(void *data, DBusMessage *msg)
+{
+   E_Bluez_Element *element = (E_Bluez_Element *)data;
+   DBusMessageIter itr, v_itr;
+   int t, r, changed = 0;
+   const char *name = NULL;
+   void *value = NULL;
+
+   DBG("Property changed in element %s", element->path);
+
+   if (!_dbus_callback_check_and_init(msg, &itr, NULL))
+      return;
+
+   t = dbus_message_iter_get_arg_type(&itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
+     {
+        ERR("missing name in property changed signal");
+        return;
+     }
+
+   dbus_message_iter_get_basic(&itr, &name);
+
+   dbus_message_iter_next(&itr);
+   t = dbus_message_iter_get_arg_type(&itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_VARIANT))
+     {
+        ERR("missing value in property changed signal");
+        return;
+     }
+
+   dbus_message_iter_recurse(&itr, &v_itr);
+   t = dbus_message_iter_get_arg_type(&v_itr);
+
+   if (t == DBUS_TYPE_ARRAY)
+     {
+        value = e_bluez_element_iter_get_array(&v_itr, name);
+     }
+   else if (t != DBUS_TYPE_INVALID)
+     {
+        dbus_message_iter_get_basic(&v_itr, &value);
+     }
+   else
+     {
+        ERR("property has invalid type %s", name);
+        return;
+     }
+
+   r = _e_bluez_element_property_value_add(element, name, t, value);
+   if (r < 0)
+     {
+        ERR("failed to add property value %s (%c)", name, t);
+     }
+   else if (r == 1)
+     {
+        INF("property value changed %s (%c)", name, t);
+        changed = 1;
+     }
+
+   if (changed)
+      _e_bluez_element_listeners_call(element);
+}
+
+/**
+ * Register the given path, possible creating and element and return it.
+ *
+ * This will check if path is already registered, in that case the
+ * exiting element is returned. If it was not registered yet, a new
+ * element is created, registered and returned.
+ *
+ * This call will not add extra references to the object.
+ *
+ * @param path the path to register the element
+ *
+ * @return the registered object, no references are added.
+ */
+E_Bluez_Element *
+e_bluez_element_register(const char *path, const char *interface)
+{
+   E_Bluez_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(interface, NULL);
+
+   element = eina_hash_find(elements, path);
+   if (element)
+      return element;
+
+   element = e_bluez_element_new(path, interface);
+   if (!element)
+      return NULL;
+
+   if (!eina_hash_add(elements, element->path, element))
+     {
+        ERR("could not add element %s to hash, delete it.", path);
+        e_bluez_element_free(element);
+        return NULL;
+     }
+
+   element->signal_handler =
+      e_dbus_signal_handler_add
+         (e_bluez_conn, e_bluez_system_bus_name_get(),
+         element->path, element->interface, "PropertyChanged",
+         _e_bluez_element_property_changed_callback, element);
+
+   e_bluez_element_event_add(E_BLUEZ_EVENT_ELEMENT_ADD, element);
+
+   return element;
+}
+
+static void
+_e_bluez_element_event_unregister_and_free(void *data __UNUSED__, void *ev)
+{
+   E_Bluez_Element *element = ev;
+   e_bluez_element_unref(element);
+}
+
+static void
+_e_bluez_element_unregister_internal(E_Bluez_Element *element)
+{
+   if (element->signal_handler)
+     {
+        e_dbus_signal_handler_del(e_bluez_conn, element->signal_handler);
+        element->signal_handler = NULL;
+     }
+
+   ecore_event_add(E_BLUEZ_EVENT_ELEMENT_DEL, element,
+                   _e_bluez_element_event_unregister_and_free, NULL);
+}
+
+/**
+ * Forget about the given element.
+ *
+ * This will remove the element from the pool of known objects, then
+ * add an E_BLUEZ_EVENT_ELEMENT_DEL and after that will unreference it,
+ * possible freeing it.
+ *
+ * @param element element to forget about. Its reference will be removed.
+ */
+void
+e_bluez_element_unregister(E_Bluez_Element *element)
+{
+   if (!element)
+      return;
+
+   if (elements)
+      eina_hash_del_by_key(elements, element->path);
+}
+
+/**
+ * Remove all known elements.
+ *
+ * This will remove all known elements but will NOT add any
+ * E_BLUEZ_EVENT_ELEMENT_DEL to main loop.
+ *
+ * This is just useful to make sure next e_bluez_manager_sync_elements()
+ * will not leave any stale elements. This is unlikely to happen, as
+ * E_Bluez is supposed to catch all required events to avoid stale elements.
+ */
+void
+e_bluez_manager_clear_elements(void)
+{
+   e_bluez_elements_shutdown();
+   e_bluez_elements_init();
+}
+
+/**
+ * Creates elements hash.
+ *
+ * This has no init counter since its already guarded by other code.
+ * @internal
+ */
+void
+e_bluez_elements_init(void)
+{
+   EINA_SAFETY_ON_FALSE_RETURN(!elements);
+   elements =
+      eina_hash_string_superfast_new(EINA_FREE_CB
+                                        (_e_bluez_element_unregister_internal));
+}
+
+void
+e_bluez_elements_shutdown(void)
+{
+   EINA_SAFETY_ON_FALSE_RETURN(!!elements);
+   eina_hash_free(elements);
+   elements = NULL;
+}
+
+static inline Eina_Bool
+_e_bluez_element_is(const E_Bluez_Element *element, const char *interface)
+{
+   return element->interface == interface;
+}
+
+Eina_Bool
+e_bluez_element_is_adapter(const E_Bluez_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return _e_bluez_element_is(element, e_bluez_iface_adapter);
+}
+
+Eina_Bool
+e_bluez_element_is_device(const E_Bluez_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return _e_bluez_element_is(element, e_bluez_iface_device);
+}
+
diff --git a/src/lib/bluez/e_bluez_manager.c b/src/lib/bluez/e_bluez_manager.c
new file mode 100644 (file)
index 0000000..1ab1eb5
--- /dev/null
@@ -0,0 +1,34 @@
+#include "e_bluez_private.h"
+
+/**
+ * Get the element manager.
+ *
+ * @return element pointer if found, NULL otherwise.
+ */
+E_Bluez_Element *
+e_bluez_manager_get(void)
+{
+   return e_bluez_element_get(manager_path);
+}
+
+/**
+ *
+ * Call method DefaultAdapter() on Manager.
+ * TODO: Soon this method will be replaced by ANY adapter inside BlueZ, so we
+ * won't need t to call it anymore.
+ *
+ * @param cb function to call when server replies or some error happens.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_bluez_manager_default_adapter(E_DBus_Method_Return_Cb cb, void *data)
+{
+   E_Bluez_Element *element = e_bluez_element_get(manager_path);
+   const char name[] = "DefaultAdapter";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return e_bluez_element_call_full
+             (element, name, NULL, &element->_pending.properties_get, cb, data);
+}
+
diff --git a/src/lib/bluez/e_bluez_private.h b/src/lib/bluez/e_bluez_private.h
new file mode 100644 (file)
index 0000000..6e6b863
--- /dev/null
@@ -0,0 +1,143 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *    alloca (size_t);
+#endif
+
+#include <stdio.h>
+
+#include <Eina.h>
+#include <eina_safety_checks.h>
+
+#include "E_Bluez.h"
+
+static const char manager_path[] = "/";
+
+extern const char *e_bluez_iface_manager;
+extern const char *e_bluez_iface_adapter;
+extern const char *e_bluez_iface_device;
+extern const char *e_bluez_prop_address;
+extern const char *e_bluez_prop_name;
+extern const char *e_bluez_prop_alias;
+extern const char *e_bluez_prop_class;
+extern const char *e_bluez_prop_icon;
+extern const char *e_bluez_prop_paired;
+extern const char *e_bluez_prop_trusted;
+extern const char *e_bluez_prop_connected;
+extern const char *e_bluez_prop_uuids;
+extern const char *e_bluez_prop_powered;
+extern const char *e_bluez_prop_discoverable;
+extern const char *e_bluez_prop_pairable;
+extern const char *e_bluez_prop_discoverabletimeout;
+extern const char *e_bluez_prop_pairabletimeout;
+extern const char *e_bluez_prop_discovering;
+extern const char *e_bluez_prop_devices;
+
+extern int _e_dbus_bluez_log_dom;
+
+typedef struct _E_Bluez_Element_Dict_Entry   E_Bluez_Element_Dict_Entry;
+
+struct _E_Bluez_Element_Dict_Entry
+{
+   const char *name;
+   int         type;
+   union {
+      Eina_Bool      boolean;
+      const char    *str;
+      short          i16;
+      unsigned short u16;
+      unsigned int   u32;
+      unsigned char  byte;
+      const char    *path;
+   } value;
+};
+
+#ifndef EINA_LOG_DEFAULT_COLOR
+#define EINA_LOG_DEFAULT_COLOR EINA_COLOR_CYAN
+#endif
+
+#undef DBG
+#undef INF
+#undef WRN
+#undef ERR
+
+#define DBG(...) EINA_LOG_DOM_DBG(_e_dbus_bluez_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_e_dbus_bluez_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_e_dbus_bluez_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_e_dbus_bluez_log_dom, __VA_ARGS__)
+
+static inline Eina_Bool
+_dbus_callback_check_and_init(DBusMessage *msg, DBusMessageIter *itr, DBusError *err)
+{
+   if (!msg)
+     {
+        if (err)
+           ERR("an error was reported by server: "
+               "name=\"%s\", message=\"%s\"",
+               err->name, err->message);
+        else
+           ERR("callback without message arguments!");
+
+        return EINA_FALSE;
+     }
+
+   if (!dbus_message_iter_init(msg, itr))
+     {
+        ERR("could not init iterator.");
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static inline Eina_Bool
+__dbus_iter_type_check(int type, int expected, const char *expected_name)
+{
+   if (type == expected)
+      return EINA_TRUE;
+
+   ERR("expected type %s (%c) but got %c instead!",
+       expected_name, expected, type);
+
+   return EINA_FALSE;
+}
+
+#define _dbus_iter_type_check(t, e) __dbus_iter_type_check(t, e, # e)
+
+extern E_DBus_Connection *e_bluez_conn;
+
+const char *                    e_bluez_system_bus_name_get(void);
+
+void                            e_bluez_manager_clear_elements(void);
+
+void                            e_bluez_elements_init(void);
+void                            e_bluez_elements_shutdown(void);
+
+E_Bluez_Element *               e_bluez_element_register(const char *path, const char *interface);
+void                            e_bluez_element_unregister(E_Bluez_Element *element);
+
+Eina_Bool                       e_bluez_element_message_send(E_Bluez_Element *element, const char *method_name, E_DBus_Method_Return_Cb cb, DBusMessage *msg, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data);
+E_Bluez_Array *                 e_bluez_element_iter_get_array(DBusMessageIter *itr, const char *key);
+void                            e_bluez_element_event_add(int event_type, E_Bluez_Element *element);
+E_Bluez_Element_Dict_Entry *    e_bluez_element_array_dict_find_stringshared(const E_Bluez_Array *array, const char *key);
+void                            e_bluez_element_array_free(E_Bluez_Array *array, E_Bluez_Array *new __UNUSED__);
+
+Eina_Bool                       e_bluez_element_call_full(E_Bluez_Element *element, const char *method_name, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data);
+Eina_Bool                       e_bluez_element_call_with_path(E_Bluez_Element *element, const char *method_name, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data);
+Eina_Bool                       e_bluez_element_call_with_string(E_Bluez_Element *element, const char *method_name, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data);
+Eina_Bool                       e_bluez_element_call_with_path_and_string(E_Bluez_Element *element, const char *method_name, const char *path, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data);
diff --git a/src/lib/connman0_7x/E_Connman.h b/src/lib/connman0_7x/E_Connman.h
new file mode 100644 (file)
index 0000000..06e879a
--- /dev/null
@@ -0,0 +1,251 @@
+#ifndef E_CONNMAN_H
+#define E_CONNMAN_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+#include <E_DBus.h>
+
+/**
+ * @defgroup EConnman_Group EConnman
+ *
+ * Currently supporting upstream API version 0.75 and later.
+ *
+ * @note this API is subject to changed based on upstream connman changes,
+ *       then it is required to acknowledge this by defining:
+ *       @code
+ *       #define E_CONNMAN_I_KNOW_THIS_API_IS_SUBJECT_TO_CHANGE 1
+ *       @endcode
+ *
+ * @{
+ */
+#ifndef E_CONNMAN_I_KNOW_THIS_API_IS_SUBJECT_TO_CHANGE
+#error "E_Connman.h is an unstable API linked to upstream connman project"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Ecore Events */
+extern int E_CONNMAN_EVENT_MANAGER_IN;
+extern int E_CONNMAN_EVENT_MANAGER_OUT;
+extern int E_CONNMAN_EVENT_ELEMENT_ADD;
+extern int E_CONNMAN_EVENT_ELEMENT_DEL;
+extern int E_CONNMAN_EVENT_ELEMENT_UPDATED;
+
+typedef struct _E_Connman_Element   E_Connman_Element;
+
+struct _E_Connman_Element
+{
+   const char            *path;
+   const char            *interface;
+   E_DBus_Signal_Handler *signal_handler;
+   Eina_Inlist           *props;
+
+   /* private */
+   struct
+   {
+      Eina_Inlist *properties_get;
+      Eina_Inlist *property_set;
+      Eina_Inlist *agent_register;
+      Eina_Inlist *agent_unregister;
+      Eina_Inlist *request_scan;
+      Eina_Inlist *technology_enable;
+      Eina_Inlist *technology_disable;
+      Eina_Inlist *profile_remove;
+      Eina_Inlist *service_connect;
+      Eina_Inlist *service_disconnect;
+      Eina_Inlist *service_remove;
+      Eina_Inlist *service_move_before;
+      Eina_Inlist *service_move_after;
+      Eina_Inlist *service_clear_property;
+   } _pending;
+   struct
+   {
+      Ecore_Idler *changed;
+   } _idler;
+   Eina_Inlist *_listeners;
+   int          _references;
+};
+
+/* General Public API */
+EAPI unsigned int           e_connman_system_init(E_DBus_Connection *edbus_conn) EINA_ARG_NONNULL(1);
+EAPI unsigned int           e_connman_system_shutdown(void);
+
+/* Manager Methods */
+EAPI E_Connman_Element *    e_connman_manager_get(void) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_manager_agent_register(const char *object_path, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_manager_agent_unregister(const char *object_path, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_manager_state_get(const char **state) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_manager_offline_mode_get(Eina_Bool *offline) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_manager_offline_mode_set(Eina_Bool offline, E_DBus_Method_Return_Cb cb, const void *data) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_manager_profiles_get(unsigned int *count, E_Connman_Element ***p_elements) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_manager_services_get(unsigned int *count, E_Connman_Element ***p_elements) EINA_ARG_NONNULL(1, 2)  EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_manager_technologies_get(unsigned int *count, E_Connman_Element ***p_elements) EINA_ARG_NONNULL(1, 2)  EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_manager_request_scan(const char *type, E_DBus_Method_Return_Cb cb, const void *data) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_manager_technology_default_get(const char **type) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_manager_technology_enable(const char *type, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_manager_technology_disable(const char *type, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_manager_technologies_available_get(unsigned int *count, const char ***strings) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_manager_technologies_enabled_get(unsigned int *count, const char ***strings) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_manager_technologies_connected_get(unsigned int *count, const char ***strings) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_manager_profile_remove(const E_Connman_Element *profile, E_DBus_Method_Return_Cb cb, const void *data) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_manager_profile_active_get(E_Connman_Element **profile) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_manager_profile_active_set(const E_Connman_Element *profile, E_DBus_Method_Return_Cb cb, const void *data) EINA_WARN_UNUSED_RESULT;
+
+// TODO: profile_create()
+// TODO: service_connect() (actually creates and connect)
+// TODO: signal E_CONNMAN_EVENT_MANAGER_STATE_CHANGED
+
+/* Profile Methods */
+EAPI E_Connman_Element *    e_connman_profile_get(const char *path) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_profile_name_get(const E_Connman_Element *profile, const char **name) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_profile_name_set(E_Connman_Element *profile, const char *name, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_profile_offline_mode_get(const E_Connman_Element *profile, Eina_Bool *offline) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_profile_offline_mode_set(E_Connman_Element *profile, Eina_Bool offline, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_profile_services_get(const E_Connman_Element *profile, unsigned int *count, E_Connman_Element ***p_elements) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+
+/* Services Methods */
+EAPI E_Connman_Element *    e_connman_service_get(const char *path) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_clear_property(E_Connman_Element *service, const char *property, E_DBus_Method_Return_Cb cb, const void *data);
+
+EAPI Eina_Bool              e_connman_service_remove(E_Connman_Element *service, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_connect(E_Connman_Element *service, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_disconnect(E_Connman_Element *service, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_move_before(E_Connman_Element *service, const char *object_path, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_move_after(E_Connman_Element *service, const char *object_path, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_state_get(const E_Connman_Element *service, const char **state) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_error_get(const E_Connman_Element *service, const char **error) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_name_get(const E_Connman_Element *service, const char **name) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_type_get(const E_Connman_Element *service, const char **type) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_security_get(const E_Connman_Element *service, unsigned int *count, const char ***security) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_passphrase_get(const E_Connman_Element *service, const char **passphrase) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_passphrase_set(E_Connman_Element *service, const char *passphrase, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_strength_get(const E_Connman_Element *service, unsigned char *strength) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_favorite_get(const E_Connman_Element *service, Eina_Bool *favorite) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_immutable_get(const E_Connman_Element *service, Eina_Bool *immutable) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_auto_connect_get(const E_Connman_Element *service, Eina_Bool *auto_connect) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_auto_connect_set(E_Connman_Element *service, Eina_Bool auto_connect, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_passphrase_required_get(const E_Connman_Element *service, Eina_Bool *passphrase_required) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_login_required_get(const E_Connman_Element *service, Eina_Bool *login_required) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_roaming_get(const E_Connman_Element *service, Eina_Bool *roaming) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_nameservers_get(const E_Connman_Element *service, unsigned int *count, const char ***nameserver) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_nameservers_configuration_get(const E_Connman_Element *service, unsigned int *count, const char ***nameservers) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_nameservers_configuration_set(E_Connman_Element *service, unsigned int count, const char **nameservers, E_DBus_Method_Return_Cb cb, const void *data)  EINA_ARG_NONNULL(1, 2, 3, 4, 5) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_domains_get(const E_Connman_Element *service, unsigned int *count, const char ***domains) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_ipv4_method_get(const E_Connman_Element *service, const char **method) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_ipv4_address_get(const E_Connman_Element *service, const char **address) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_ipv4_gateway_get(const E_Connman_Element *service, const char **gateway) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_ipv4_netmask_get(const E_Connman_Element *service, const char **netmask) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_ipv4_configuration_method_get(const E_Connman_Element *service, const char **method) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_ipv4_configuration_address_get(const E_Connman_Element *service, const char **address) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_ipv4_configuration_gateway_get(const E_Connman_Element *service, const char **gateway) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_ipv4_configuration_netmask_get(const E_Connman_Element *service, const char **netmask) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_proxy_method_get(const E_Connman_Element *service, const char **method) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_proxy_url_get(const E_Connman_Element *service, const char **url) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_proxy_servers_get(const E_Connman_Element *service, unsigned int *count, const char ***servers) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_proxy_excludes_get(const E_Connman_Element *service, unsigned int *count, const char ***excludes) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_proxy_configuration_method_get(const E_Connman_Element *service, const char **method) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_proxy_configuration_url_get(const E_Connman_Element *service, const char **url) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_proxy_configuration_servers_get(const E_Connman_Element *service, unsigned int *count, const char ***servers) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_proxy_configuration_excludes_get(const E_Connman_Element *service, unsigned int *count, const char ***excludes) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_service_ethernet_method_get(const E_Connman_Element *service, const char **method) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_ethernet_interface_get(const E_Connman_Element *service, const char **iface) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_ethernet_address_get(const E_Connman_Element *service, const char **address) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_ethernet_mtu_get(const E_Connman_Element *service, unsigned short *mtu) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_ethernet_speed_get(const E_Connman_Element *service, unsigned short *speed) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_ethernet_duplex_get(const E_Connman_Element *service, const char **duplex) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+/* Methods to configure IPv4 service */
+EAPI Eina_Bool              e_connman_service_ipv4_configure_dhcp(E_Connman_Element *service, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_service_ipv4_configure_manual(E_Connman_Element *service, const char *address, const char *netmask, const char *gateway, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+/* Technologies methods */
+EAPI E_Connman_Element *    e_connman_technology_get(const char *path) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_technology_state_get(const E_Connman_Element *technology, const char **state) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_technology_name_get(const E_Connman_Element *technology, const char **state) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_technology_type_get(const E_Connman_Element *technology, const char **state) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+/* Low-Level API:
+ *
+ * Should just be used to work around problems until proper solution
+ * is made into e_connman.
+ */
+EAPI Eina_Bool              e_connman_manager_sync_elements(void);
+
+EAPI Eina_Bool              e_connman_elements_get_all(unsigned int *count, E_Connman_Element ***p_elements) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_elements_get_all_type(const char *type, unsigned int *count, E_Connman_Element ***p_elements) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI E_Connman_Element *    e_connman_element_get(const char *path);
+
+EAPI void                   e_connman_element_listener_add(E_Connman_Element *element, void (*cb)(void *data, const E_Connman_Element *element), const void *data, void (*free_data)(void *data)) EINA_ARG_NONNULL(1, 2);
+EAPI void                   e_connman_element_listener_del(E_Connman_Element *element, void (*cb)(void *data, const E_Connman_Element *element), const void *data) EINA_ARG_NONNULL(1, 2);
+
+EAPI int                    e_connman_element_ref(E_Connman_Element *element) EINA_ARG_NONNULL(1);
+EAPI int                    e_connman_element_unref(E_Connman_Element *element) EINA_ARG_NONNULL(1);
+
+EAPI void                   e_connman_element_print(FILE *fp, const E_Connman_Element *element) EINA_ARG_NONNULL(1, 2);
+
+EAPI Eina_Bool              e_connman_element_properties_sync(E_Connman_Element *element) EINA_ARG_NONNULL(1);
+EAPI Eina_Bool              e_connman_element_properties_sync_full(E_Connman_Element *element, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1);
+EAPI void                   e_connman_element_properties_list(const E_Connman_Element *element, Eina_Bool (*cb)(void *data, const E_Connman_Element *element, const char *name, int type, const void *value), const void *data) EINA_ARG_NONNULL(1, 2);
+
+EAPI Eina_Bool              e_connman_element_property_set(E_Connman_Element *element, const char *prop, int type, const void *value) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_element_property_set_full(E_Connman_Element *element, const char *prop, int type, const void *value, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_element_property_array_set_full(E_Connman_Element *element, const char *prop, int type, unsigned int count, const void * const *values, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_element_property_dict_set_full(E_Connman_Element *element, const char *prop, const char *key, int type, const void *value, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_element_property_type_get_stringshared(const E_Connman_Element *element, const char *name, int *type) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_element_property_type_get(const E_Connman_Element *element, const char *name, int *type) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_element_property_dict_get_stringshared(const E_Connman_Element *element, const char *dict_name, const char *key_name, int *type, void *value) EINA_ARG_NONNULL(1, 2, 4) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_element_property_dict_strings_array_get_stringshared(const E_Connman_Element *element, const char *dict_name, const char *key, unsigned int *count, const char ***strings) EINA_ARG_NONNULL(1, 2, 3, 4) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_element_property_get_stringshared(const E_Connman_Element *element, const char *name, int *type, void *value) EINA_ARG_NONNULL(1, 2, 4) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_element_property_get(const E_Connman_Element *element, const char *name, int *type, void *value) EINA_ARG_NONNULL(1, 2, 4) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool              e_connman_element_is_manager(const E_Connman_Element *element) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_element_is_profile(const E_Connman_Element *element) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_element_is_service(const E_Connman_Element *element) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool              e_connman_element_is_technology(const E_Connman_Element *element) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+
+#endif /* E_CONNMAN_H */
diff --git a/src/lib/connman0_7x/Makefile.am b/src/lib/connman0_7x/Makefile.am
new file mode 100644 (file)
index 0000000..1d645c2
--- /dev/null
@@ -0,0 +1,24 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I $(top_srcdir)/src/lib/dbus \
+@EDBUS_CFLAGS@
+
+lib_LTLIBRARIES = libeconnman0_7x.la
+includes_HEADERS = E_Connman.h
+includesdir = $(includedir)/e_dbus-@VMAJ@/connman0_7x
+
+libeconnman0_7x_la_SOURCES = \
+e_connman.c \
+e_connman_element.c \
+e_connman_manager.c \
+e_connman_profile.c \
+e_connman_service.c \
+e_connman_technology.c
+
+libeconnman0_7x_la_LIBADD = \
+@EDBUS_LIBS@ $(top_builddir)/src/lib/dbus/libedbus.la
+
+libeconnman0_7x_la_LDFLAGS = -version-info @version_info@ @release_info@
+
+EXTRA_DIST = e_connman_private.h
diff --git a/src/lib/connman0_7x/e_connman.c b/src/lib/connman0_7x/e_connman.c
new file mode 100644 (file)
index 0000000..2302bcd
--- /dev/null
@@ -0,0 +1,439 @@
+#include "e_connman_private.h"
+#include <stdlib.h>
+#include <string.h>
+
+static E_DBus_Signal_Handler *cb_name_owner_changed = NULL;
+static DBusPendingCall *pending_get_name_owner = NULL;
+static unsigned int init_count = 0;
+static char *unique_name = NULL;
+
+static const char bus_name[] = "net.connman";
+
+E_DBus_Connection *e_connman_conn = NULL;
+
+EAPI int E_CONNMAN_EVENT_MANAGER_IN = 0;
+EAPI int E_CONNMAN_EVENT_MANAGER_OUT = 0;
+EAPI int E_CONNMAN_EVENT_ELEMENT_ADD = 0;
+EAPI int E_CONNMAN_EVENT_ELEMENT_DEL = 0;
+EAPI int E_CONNMAN_EVENT_ELEMENT_UPDATED = 0;
+
+const char *e_connman_iface_manager = NULL;
+const char *e_connman_iface_profile = NULL;
+const char *e_connman_iface_service = NULL;
+const char *e_connman_iface_connection = NULL;
+const char *e_connman_iface_technology = NULL;
+
+const char *e_connman_prop_ipv4 = NULL;
+const char *e_connman_prop_ipv4_configuration = NULL;
+const char *e_connman_prop_ethernet = NULL;
+const char *e_connman_prop_interface = NULL;
+const char *e_connman_prop_speed = NULL;
+const char *e_connman_prop_duplex = NULL;
+const char *e_connman_prop_method = NULL;
+const char *e_connman_prop_address = NULL;
+const char *e_connman_prop_gateway = NULL;
+const char *e_connman_prop_netmask = NULL;
+const char *e_connman_prop_mtu = NULL;
+const char *e_connman_prop_name = NULL;
+const char *e_connman_prop_offline_mode = NULL;
+const char *e_connman_prop_profiles = NULL;
+const char *e_connman_prop_profile_active = NULL;
+const char *e_connman_prop_services = NULL;
+const char *e_connman_prop_technologies = NULL;
+const char *e_connman_prop_state = NULL;
+const char *e_connman_prop_strength = NULL;
+const char *e_connman_prop_type = NULL;
+const char *e_connman_prop_error = NULL;
+const char *e_connman_prop_security = NULL;
+const char *e_connman_prop_passphrase = NULL;
+const char *e_connman_prop_passphrase_required = NULL;
+const char *e_connman_prop_login_required = NULL;
+const char *e_connman_prop_favorite = NULL;
+const char *e_connman_prop_immutable = NULL;
+const char *e_connman_prop_auto_connect = NULL;
+const char *e_connman_prop_roaming = NULL;
+const char *e_connman_prop_technology_default = NULL;
+const char *e_connman_prop_technologies_available = NULL;
+const char *e_connman_prop_technologies_enabled = NULL;
+const char *e_connman_prop_technologies_connected = NULL;
+const char *e_connman_prop_nameservers = NULL;
+const char *e_connman_prop_nameservers_configuration = NULL;
+const char *e_connman_prop_domains = NULL;
+const char *e_connman_prop_domains_configuration = NULL;
+const char *e_connman_prop_proxy = NULL;
+const char *e_connman_prop_proxy_configuration = NULL;
+const char *e_connman_prop_url = NULL;
+const char *e_connman_prop_servers = NULL;
+const char *e_connman_prop_excludes = NULL;
+
+int _e_dbus_connman_log_dom = -1;
+
+const char *
+e_connman_system_bus_name_get(void)
+{
+   return unique_name ? unique_name : bus_name;
+}
+
+/***********************************************************************
+* Manager
+***********************************************************************/
+
+/**
+ * Synchronize elements with server.
+ *
+ * This will call Manager.GetProperties() on server, retrieve properties
+ * and some element paths and then request their properties.
+ *
+ * This call will add events E_CONNMAN_EVENT_ELEMENT_ADD and
+ * E_CONNMAN_EVENT_ELEMENT_UPDATED to the main loop.
+ *
+ * This will not remove stale elements.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_sync_elements(void)
+{
+   E_Connman_Element *manager;
+
+   if (!unique_name)
+      return EINA_FALSE;
+
+   manager = e_connman_element_register(manager_path, e_connman_iface_manager);
+   if (manager)
+      e_connman_element_properties_sync(manager);
+   else
+      return EINA_FALSE;
+
+   DBG("sync_manager: %s (%s)", unique_name, bus_name);
+
+   return EINA_TRUE;
+}
+
+static void
+_e_connman_system_name_owner_exit(void)
+{
+   e_connman_manager_clear_elements();
+   ecore_event_add(E_CONNMAN_EVENT_MANAGER_OUT, NULL, NULL, NULL);
+
+   free(unique_name);
+   unique_name = NULL;
+}
+
+static void
+_e_connman_system_name_owner_enter(const char *uid)
+{
+   DBG("enter connman at %s (old was %s)", uid, unique_name);
+   if (unique_name && strcmp(unique_name, uid) == 0)
+     {
+        DBG("same unique_name for connman, ignore.");
+        return;
+     }
+
+   if (unique_name)
+      _e_connman_system_name_owner_exit();
+
+   unique_name = strdup(uid);
+
+   ecore_event_add(E_CONNMAN_EVENT_MANAGER_IN, NULL, NULL, NULL);
+   e_connman_manager_sync_elements();
+}
+
+static void
+_e_connman_system_name_owner_changed(void *data __UNUSED__, DBusMessage *msg)
+{
+   DBusError err;
+   const char *name, *from, *to;
+
+   dbus_error_init(&err);
+   if (!dbus_message_get_args(msg, &err,
+                              DBUS_TYPE_STRING, &name,
+                              DBUS_TYPE_STRING, &from,
+                              DBUS_TYPE_STRING, &to,
+                              DBUS_TYPE_INVALID))
+     {
+        ERR("could not get NameOwnerChanged arguments: %s: %s",
+            err.name, err.message);
+        dbus_error_free(&err);
+        return;
+     }
+
+   if (strcmp(name, bus_name) != 0)
+      return;
+
+   DBG("NameOwnerChanged from=[%s] to=[%s]", from, to);
+
+   if (from[0] == '\0' && to[0] != '\0')
+     {
+        _e_connman_system_name_owner_enter(to);
+     }
+   else if (from[0] != '\0' && to[0] == '\0')
+     {
+        DBG("exit connman at %s", from);
+        if (strcmp(unique_name, from) != 0)
+           DBG("%s was not the known name %s, ignored.", from, unique_name);
+        else
+           _e_connman_system_name_owner_exit();
+     }
+   else
+     {
+        DBG("unknow change from %s to %s", from, to);
+     }
+}
+
+static void
+_e_connman_get_name_owner(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
+{
+   DBusMessageIter itr;
+   int t;
+   const char *uid;
+
+   pending_get_name_owner = NULL;
+
+   if (!_dbus_callback_check_and_init(msg, &itr, err))
+      return;
+
+   t = dbus_message_iter_get_arg_type(&itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
+      return;
+
+   dbus_message_iter_get_basic(&itr, &uid);
+   if (!uid)
+     {
+        ERR("no name owner!");
+        return;
+     }
+
+   _e_connman_system_name_owner_enter(uid);
+   return;
+}
+
+/**
+ * Initialize E Connection Manager (E_Connman) system.
+ *
+ * This will connect and watch net.connman.Manager and Element
+ * events and translate to Ecore main loop events, also provide a
+ * proxy for method invocation on server.
+ *
+ * Interesting events are:
+ *   - E_CONNMAN_EVENT_MANAGER_IN: issued when connman is avaiable.
+ *   - E_CONNMAN_EVENT_MANAGER_OUT: issued when connman connection is lost.
+ *   - E_CONNMAN_EVENT_ELEMENT_ADD: element was added.
+ *   - E_CONNMAN_EVENT_ELEMENT_DEL: element was deleted.
+ *   - E_CONNMAN_EVENT_ELEMENT_UPDATED: element was updated (properties
+ *     or state changed).
+ *
+ * Manager IN/OUT events do not provide any event information, just
+ * tells you that system is usable or not. After manager is out, all
+ * elements will be removed, so after this event do not use the system anymore.
+ *
+ * Element events will give you an element object. After DEL event callback
+ * returns, that element will not be valid anymore.
+ */
+unsigned int
+e_connman_system_init(E_DBus_Connection *edbus_conn)
+{
+   init_count++;
+
+   if (init_count > 1)
+      return init_count;
+
+   _e_dbus_connman_log_dom = eina_log_domain_register
+         ("e_dbus_connman", EINA_LOG_DEFAULT_COLOR);
+
+   if (_e_dbus_connman_log_dom < 0)
+     {
+        EINA_LOG_ERR
+           ("impossible to create a log domain for edbus_connman module");
+        return -1;
+     }
+
+   if (E_CONNMAN_EVENT_MANAGER_IN == 0)
+      E_CONNMAN_EVENT_MANAGER_IN = ecore_event_type_new();
+
+   if (E_CONNMAN_EVENT_MANAGER_OUT == 0)
+      E_CONNMAN_EVENT_MANAGER_OUT = ecore_event_type_new();
+
+   if (E_CONNMAN_EVENT_ELEMENT_ADD == 0)
+      E_CONNMAN_EVENT_ELEMENT_ADD = ecore_event_type_new();
+
+   if (E_CONNMAN_EVENT_ELEMENT_DEL == 0)
+      E_CONNMAN_EVENT_ELEMENT_DEL = ecore_event_type_new();
+
+   if (E_CONNMAN_EVENT_ELEMENT_UPDATED == 0)
+      E_CONNMAN_EVENT_ELEMENT_UPDATED = ecore_event_type_new();
+
+#define ADD_STRINGSHARE(name, s)       \
+   if (!name)                          \
+      name = eina_stringshare_add(s)
+
+   ADD_STRINGSHARE(e_connman_iface_manager, "net.connman.Manager");
+   ADD_STRINGSHARE(e_connman_iface_profile, "net.connman.Profile");
+   ADD_STRINGSHARE(e_connman_iface_service, "net.connman.Service");
+   ADD_STRINGSHARE(e_connman_iface_connection, "net.connman.Connection");
+   ADD_STRINGSHARE(e_connman_iface_technology, "net.connman.Technology");
+   ADD_STRINGSHARE(e_connman_prop_ipv4, "IPv4");
+   ADD_STRINGSHARE(e_connman_prop_ipv4_configuration, "IPv4.Configuration");
+   ADD_STRINGSHARE(e_connman_prop_ethernet, "Ethernet");
+   ADD_STRINGSHARE(e_connman_prop_interface, "Interface");
+   ADD_STRINGSHARE(e_connman_prop_speed, "Speed");
+   ADD_STRINGSHARE(e_connman_prop_duplex, "Duplex");
+   ADD_STRINGSHARE(e_connman_prop_method, "Method");
+   ADD_STRINGSHARE(e_connman_prop_address, "Address");
+   ADD_STRINGSHARE(e_connman_prop_gateway, "Gateway");
+   ADD_STRINGSHARE(e_connman_prop_netmask, "Netmask");
+   ADD_STRINGSHARE(e_connman_prop_mtu, "MTU");
+   ADD_STRINGSHARE(e_connman_prop_name, "Name");
+   ADD_STRINGSHARE(e_connman_prop_offline_mode, "OfflineMode");
+   ADD_STRINGSHARE(e_connman_prop_profiles, "Profiles");
+   ADD_STRINGSHARE(e_connman_prop_profile_active, "ActiveProfile");
+   ADD_STRINGSHARE(e_connman_prop_services, "Services");
+   ADD_STRINGSHARE(e_connman_prop_technologies, "Technologies");
+   ADD_STRINGSHARE(e_connman_prop_state, "State");
+   ADD_STRINGSHARE(e_connman_prop_strength, "Strength");
+   ADD_STRINGSHARE(e_connman_prop_type, "Type");
+   ADD_STRINGSHARE(e_connman_prop_error, "Error");
+   ADD_STRINGSHARE(e_connman_prop_security, "Security");
+   ADD_STRINGSHARE(e_connman_prop_passphrase, "Passphrase");
+   ADD_STRINGSHARE(e_connman_prop_passphrase_required, "PassphraseRequired");
+   ADD_STRINGSHARE(e_connman_prop_login_required, "LoginRequired");
+   ADD_STRINGSHARE(e_connman_prop_favorite, "Favorite");
+   ADD_STRINGSHARE(e_connman_prop_immutable, "Immutable");
+   ADD_STRINGSHARE(e_connman_prop_auto_connect, "AutoConnect");
+   ADD_STRINGSHARE(e_connman_prop_roaming, "Roaming");
+   ADD_STRINGSHARE(e_connman_prop_technology_default, "DefaultTechnology");
+   ADD_STRINGSHARE(e_connman_prop_technologies_available,
+                   "AvailableTechnologies");
+   ADD_STRINGSHARE(e_connman_prop_technologies_enabled, "EnabledTechnologies");
+   ADD_STRINGSHARE(e_connman_prop_technologies_connected,
+                   "ConnectedTechnologies");
+   ADD_STRINGSHARE(e_connman_prop_nameservers, "Nameservers");
+   ADD_STRINGSHARE(e_connman_prop_nameservers_configuration,
+                   "Nameservers.Configuration");
+   ADD_STRINGSHARE(e_connman_prop_domains, "Domains");
+   ADD_STRINGSHARE(e_connman_prop_domains_configuration,
+                   "Domains.Configuration");
+   ADD_STRINGSHARE(e_connman_prop_proxy, "Proxy");
+   ADD_STRINGSHARE(e_connman_prop_proxy_configuration, "Proxy.Configuration");
+   ADD_STRINGSHARE(e_connman_prop_url, "URL");
+   ADD_STRINGSHARE(e_connman_prop_servers, "Servers");
+   ADD_STRINGSHARE(e_connman_prop_excludes, "Excludes");
+
+#undef ADD_STRINGSHARE
+
+   e_connman_conn = edbus_conn;
+   cb_name_owner_changed = e_dbus_signal_handler_add
+         (e_connman_conn, E_DBUS_FDO_BUS, E_DBUS_FDO_PATH, E_DBUS_FDO_INTERFACE, "NameOwnerChanged",
+         _e_connman_system_name_owner_changed, NULL);
+
+   if (pending_get_name_owner)
+      dbus_pending_call_cancel(pending_get_name_owner);
+
+   pending_get_name_owner = e_dbus_get_name_owner
+         (e_connman_conn, bus_name, _e_connman_get_name_owner, NULL);
+
+   e_connman_elements_init();
+
+   return init_count;
+}
+
+static inline void
+_stringshare_del(const char **str)
+{
+   if (!*str)
+      return;
+
+   eina_stringshare_del(*str);
+   *str = NULL;
+}
+
+/**
+ * Shutdown connman system.
+ *
+ * When count drops to 0 resources will be released and no calls should be
+ * made anymore.
+ */
+unsigned int
+e_connman_system_shutdown(void)
+{
+   if (init_count == 0)
+     {
+        ERR("connman system already shut down.");
+        return 0;
+     }
+
+   init_count--;
+   if (init_count > 0)
+      return init_count;
+
+   _stringshare_del(&e_connman_iface_manager);
+   _stringshare_del(&e_connman_iface_profile);
+   _stringshare_del(&e_connman_iface_service);
+   _stringshare_del(&e_connman_iface_connection);
+   _stringshare_del(&e_connman_iface_technology);
+
+   _stringshare_del(&e_connman_prop_ipv4);
+   _stringshare_del(&e_connman_prop_ipv4_configuration);
+   _stringshare_del(&e_connman_prop_ethernet);
+   _stringshare_del(&e_connman_prop_interface);
+   _stringshare_del(&e_connman_prop_speed);
+   _stringshare_del(&e_connman_prop_duplex);
+   _stringshare_del(&e_connman_prop_method);
+   _stringshare_del(&e_connman_prop_address);
+   _stringshare_del(&e_connman_prop_gateway);
+   _stringshare_del(&e_connman_prop_netmask);
+   _stringshare_del(&e_connman_prop_mtu);
+   _stringshare_del(&e_connman_prop_name);
+   _stringshare_del(&e_connman_prop_offline_mode);
+   _stringshare_del(&e_connman_prop_profiles);
+   _stringshare_del(&e_connman_prop_profile_active);
+   _stringshare_del(&e_connman_prop_services);
+   _stringshare_del(&e_connman_prop_technologies);
+   _stringshare_del(&e_connman_prop_state);
+   _stringshare_del(&e_connman_prop_strength);
+   _stringshare_del(&e_connman_prop_type);
+   _stringshare_del(&e_connman_prop_error);
+   _stringshare_del(&e_connman_prop_security);
+   _stringshare_del(&e_connman_prop_passphrase);
+   _stringshare_del(&e_connman_prop_passphrase_required);
+   _stringshare_del(&e_connman_prop_login_required);
+   _stringshare_del(&e_connman_prop_favorite);
+   _stringshare_del(&e_connman_prop_immutable);
+   _stringshare_del(&e_connman_prop_auto_connect);
+   _stringshare_del(&e_connman_prop_roaming);
+   _stringshare_del(&e_connman_prop_technology_default);
+   _stringshare_del(&e_connman_prop_technologies_available);
+   _stringshare_del(&e_connman_prop_technologies_enabled);
+   _stringshare_del(&e_connman_prop_technologies_connected);
+   _stringshare_del(&e_connman_prop_nameservers);
+   _stringshare_del(&e_connman_prop_nameservers_configuration);
+   _stringshare_del(&e_connman_prop_domains);
+   _stringshare_del(&e_connman_prop_domains_configuration);
+   _stringshare_del(&e_connman_prop_proxy);
+   _stringshare_del(&e_connman_prop_proxy_configuration);
+   _stringshare_del(&e_connman_prop_url);
+   _stringshare_del(&e_connman_prop_servers);
+   _stringshare_del(&e_connman_prop_excludes);
+
+   if (pending_get_name_owner)
+     {
+        dbus_pending_call_cancel(pending_get_name_owner);
+        pending_get_name_owner = NULL;
+     }
+
+   if (cb_name_owner_changed)
+     {
+        e_dbus_signal_handler_del(e_connman_conn, cb_name_owner_changed);
+        cb_name_owner_changed = NULL;
+     }
+
+   if (unique_name)
+      _e_connman_system_name_owner_exit();
+
+   e_connman_elements_shutdown();
+   eina_log_domain_unregister(_e_dbus_connman_log_dom);
+   e_connman_conn = NULL;
+
+   return init_count;
+}
+
diff --git a/src/lib/connman0_7x/e_connman_element.c b/src/lib/connman0_7x/e_connman_element.c
new file mode 100644 (file)
index 0000000..336c0c7
--- /dev/null
@@ -0,0 +1,2504 @@
+#include "e_connman_private.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+static Eina_Hash *elements = NULL;
+
+typedef struct _E_Connman_Element_Pending      E_Connman_Element_Pending;
+typedef struct _E_Connman_Element_Call_Data    E_Connman_Element_Call_Data;
+typedef struct _E_Connman_Element_Property     E_Connman_Element_Property;
+typedef struct _E_Connman_Element_Listener     E_Connman_Element_Listener;
+typedef struct _E_Connman_Element_Dict_Entry   E_Connman_Element_Dict_Entry;
+
+struct _E_Connman_Element_Pending
+{
+                           EINA_INLIST;
+   DBusPendingCall        *pending;
+   void                   *data;
+   E_DBus_Method_Return_Cb user_cb;
+   void                   *user_data;
+};
+
+struct _E_Connman_Element_Call_Data
+{
+   E_Connman_Element         *element;
+   E_DBus_Method_Return_Cb    cb;
+   E_Connman_Element_Pending *pending;
+   Eina_Inlist              **p_list;
+};
+
+struct _E_Connman_Element_Property
+{
+               EINA_INLIST;
+   const char *name;
+   int         type;
+   union {
+      Eina_Bool        boolean;
+      const char      *str;
+      unsigned short   u16;
+      unsigned int     u32;
+      unsigned char    byte;
+      const char      *path;
+      void            *variant;
+      E_Connman_Array *array;
+   } value;
+};
+
+struct _E_Connman_Element_Dict_Entry
+{
+   const char *name;
+   int         type;
+   union {
+      Eina_Bool        boolean;
+      const char      *str;
+      unsigned short   u16;
+      unsigned int     u32;
+      unsigned char    byte;
+      const char      *path;
+      E_Connman_Array *array;
+   } value;
+};
+
+struct _E_Connman_Element_Listener
+{
+         EINA_INLIST;
+   void  (*cb)(void *data, const E_Connman_Element *element);
+   void *data;
+   void  (*free_data)(void *data);
+};
+
+static void
+_e_connman_element_event_no_free(void *data __UNUSED__, void *ev)
+{
+   E_Connman_Element *element = ev;
+   e_connman_element_unref(element);
+}
+
+static void
+e_connman_element_event_add(int event_type, E_Connman_Element *element)
+{
+   e_connman_element_ref(element);
+   ecore_event_add
+      (event_type, element, _e_connman_element_event_no_free, element);
+}
+
+static void
+e_connman_element_call_dispatch_and_free(void *d, DBusMessage *msg, DBusError *err)
+{
+   E_Connman_Element_Call_Data *data = d;
+   E_Connman_Element_Pending *pending;
+
+   pending = data->pending;
+   pending->pending = NULL;
+
+   if (data->cb)
+      data->cb(data->element, msg, err);
+
+   if (pending->user_cb)
+      pending->user_cb(pending->user_data, msg, err);
+
+   pending->data = NULL;
+   *data->p_list = eina_inlist_remove(*data->p_list, EINA_INLIST_GET(pending));
+   free(pending);
+   free(data);
+}
+
+static void
+e_connman_element_pending_cancel_and_free(Eina_Inlist **pending)
+{
+   while (*pending)
+     {
+        E_Connman_Element_Pending *p = (E_Connman_Element_Pending *)*pending;
+        DBusError err;
+
+        dbus_pending_call_cancel(p->pending);
+
+        dbus_error_init(&err);
+        dbus_set_error(&err, "Canceled", "Pending method call was canceled.");
+        e_connman_element_call_dispatch_and_free(p->data, NULL, &err);
+        dbus_error_free(&err);
+     }
+}
+
+void
+e_connman_element_listener_add(E_Connman_Element *element, void (*cb)(void *data, const E_Connman_Element *element), const void *data, void (*free_data)(void *data))
+{
+   E_Connman_Element_Listener *l;
+   EINA_SAFETY_ON_FALSE_GOTO(element, error);
+   EINA_SAFETY_ON_FALSE_GOTO(cb, error);
+
+   l = malloc(sizeof(*l));
+   if (!l)
+     {
+        ERR("could not allocate E_Connman_Element_Listener");
+        goto error;
+     }
+
+   l->cb = cb;
+   l->data = (void *)data;
+   l->free_data = free_data;
+
+   element->_listeners = eina_inlist_append
+         (element->_listeners, EINA_INLIST_GET(l));
+
+   return;
+
+error:
+   if (free_data)
+      free_data((void *)data);
+}
+
+void
+e_connman_element_listener_del(E_Connman_Element *element, void (*cb)(void *data, const E_Connman_Element *element), const void *data)
+{
+   E_Connman_Element_Listener *l;
+
+   EINA_SAFETY_ON_NULL_RETURN(element);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+
+   EINA_INLIST_FOREACH(element->_listeners, l)
+   if ((l->cb == cb) && (l->data == data))
+     {
+        element->_listeners = eina_inlist_remove
+              (element->_listeners, EINA_INLIST_GET(l));
+        if (l->free_data)
+           l->free_data(l->data);
+
+        free(l);
+        return;
+     }
+}
+
+static void
+_e_connman_element_listeners_call_do(E_Connman_Element *element)
+{
+   E_Connman_Element_Listener *l;
+   Eina_Inlist *x;
+
+   /* NB: iterate on a copy in order to allow listeners to be deleted
+    * from callbacks.  number of listeners should be small, so the
+    * following should do fine.
+    */
+   if (eina_inlist_count(element->_listeners) < 1) goto end;
+
+   EINA_INLIST_FOREACH_SAFE(element->_listeners, x, l)
+     l->cb(l->data, element);
+
+end:
+   e_connman_element_event_add(E_CONNMAN_EVENT_ELEMENT_UPDATED, element);
+}
+
+static Eina_Bool
+_e_connman_element_listeners_call_idler(void *data)
+{
+   E_Connman_Element *element = data;
+   _e_connman_element_listeners_call_do(element);
+   element->_idler.changed = NULL;
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_e_connman_element_listeners_call(E_Connman_Element *element)
+{
+   if (element->_idler.changed)
+      return;
+
+   element->_idler.changed = ecore_idler_add
+         (_e_connman_element_listeners_call_idler, element);
+}
+
+/***********************************************************************
+* Property
+***********************************************************************/
+
+static void
+_e_connman_element_dict_entry_free(E_Connman_Element_Dict_Entry *entry)
+{
+   switch (entry->type)
+     {
+      case DBUS_TYPE_BOOLEAN:
+      case DBUS_TYPE_BYTE:
+      case DBUS_TYPE_UINT16:
+      case DBUS_TYPE_UINT32:
+         break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+         eina_stringshare_del(entry->value.path);
+         break;
+
+      case DBUS_TYPE_STRING:
+         eina_stringshare_del(entry->value.str);
+         break;
+
+      default:
+         ERR("don't know how to free dict entry '%s' of type %c (%d)",
+             entry->name, entry->type, entry->type);
+     }
+
+   eina_stringshare_del(entry->name);
+   free(entry);
+}
+
+static E_Connman_Element_Dict_Entry *
+_e_connman_element_dict_entry_new(DBusMessageIter *itr)
+{
+   E_Connman_Element_Dict_Entry *entry;
+   DBusMessageIter e_itr, v_itr;
+   int t;
+   const char *key = NULL;
+   void *value = NULL;
+
+   dbus_message_iter_recurse(itr, &e_itr);
+
+   t = dbus_message_iter_get_arg_type(&e_itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
+     {
+        ERR("invalid format for dict entry. first type not a string: %c (%d)",
+            t, t);
+        return NULL;
+     }
+
+   dbus_message_iter_get_basic(&e_itr, &key);
+   if (!key || !key[0])
+     {
+        ERR("invalid format for dict entry. no key.");
+        return NULL;
+     }
+
+   dbus_message_iter_next(&e_itr);
+   t = dbus_message_iter_get_arg_type(&e_itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_VARIANT))
+     {
+        ERR("invalid format for dict entry '%s'. "
+            "second type not a variant: %c (%d)",
+            key, t, t);
+        return NULL;
+     }
+
+   dbus_message_iter_recurse(&e_itr, &v_itr);
+
+   t = dbus_message_iter_get_arg_type(&v_itr);
+   if ((t == DBUS_TYPE_INVALID) || (t == DBUS_TYPE_ARRAY))
+     {
+        ERR("invalid type for dict value for entry '%s': %c (%d)",
+            key, t, t);
+        return NULL;
+     }
+
+   entry = calloc(1, sizeof(*entry));
+   if (!entry)
+     {
+        ERR("could not allocate memory for dict entry.");
+        return NULL;
+     }
+
+   dbus_message_iter_get_basic(&v_itr, &value);
+   switch (t)
+     {
+      case DBUS_TYPE_BOOLEAN:
+         entry->value.boolean = (Eina_Bool)(long)value;
+         break;
+
+      case DBUS_TYPE_BYTE:
+         entry->value.byte = (unsigned char)(long)value;
+         break;
+
+      case DBUS_TYPE_UINT16:
+         entry->value.u16 = (unsigned short)(long)value;
+         break;
+
+      case DBUS_TYPE_UINT32:
+         entry->value.u32 = (unsigned int)(long)value;
+         break;
+
+      case DBUS_TYPE_STRING:
+         entry->value.str = eina_stringshare_add(value);
+         break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+         entry->value.path = eina_stringshare_add(value);
+         break;
+
+      default:
+         ERR("don't know how to create dict entry '%s' for of type %c (%d)",
+             key, t, t);
+         free(entry);
+         return NULL;
+     }
+
+   entry->name = eina_stringshare_add(key);
+   entry->type = t;
+   return entry;
+}
+
+static E_Connman_Element_Dict_Entry *
+_e_connman_element_array_dict_find_stringshared(const E_Connman_Array *array, const char *key)
+{
+   E_Connman_Element_Dict_Entry *entry;
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+
+   EINA_ARRAY_ITER_NEXT(array->array, i, entry, iterator)
+   if (entry->name == key)
+      return entry;
+
+   return NULL;
+}
+
+static void
+_e_connman_element_array_free(E_Connman_Array *array, E_Connman_Array *new __UNUSED__)
+{
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+   void *item;
+
+   if (!array)
+      return;
+
+   switch (array->type)
+     {
+      case DBUS_TYPE_BOOLEAN:
+      case DBUS_TYPE_BYTE:
+      case DBUS_TYPE_UINT16:
+      case DBUS_TYPE_UINT32:
+         break;
+
+      case DBUS_TYPE_STRING:
+      case DBUS_TYPE_OBJECT_PATH:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+            eina_stringshare_del(item);
+         break;
+
+      case DBUS_TYPE_DICT_ENTRY:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         _e_connman_element_dict_entry_free(item);
+         break;
+
+      default:
+         ERR("don't know how to free array of values of type %c (%d)",
+             array->type, array->type);
+         break;
+     }
+   eina_array_free(array->array);
+   free(array);
+}
+
+static void
+_e_connman_element_property_value_free(E_Connman_Element_Property *property)
+{
+   switch (property->type)
+     {
+      case 0:
+         return;
+
+      case DBUS_TYPE_BOOLEAN:
+      case DBUS_TYPE_BYTE:
+      case DBUS_TYPE_UINT16:
+      case DBUS_TYPE_UINT32:
+         break;
+
+      case DBUS_TYPE_STRING:
+         eina_stringshare_del(property->value.str);
+         break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+         eina_stringshare_del(property->value.path);
+         break;
+
+      case DBUS_TYPE_ARRAY:
+         _e_connman_element_array_free(property->value.array, NULL);
+         break;
+
+      default:
+         ERR("don't know how to free value of property type %c (%d)",
+             property->type, property->type);
+     }
+}
+
+static const char *
+_e_connman_element_get_interface(const char *key)
+{
+   const char *interface = NULL, *tail;
+   char head;
+
+   head = key[0];
+   tail = key + 1;
+
+   switch (head)
+     {
+      case 'P':
+         if (strcmp(tail, "rofiles") == 0)
+            interface = e_connman_iface_profile;
+
+         break;
+
+      case 'S':
+         if (strcmp(tail, "ervices") == 0)
+            interface = e_connman_iface_service;
+
+         break;
+
+      case 'T':
+         if (strcmp(tail, "echnologies") == 0)
+            interface = e_connman_iface_technology;
+
+         break;
+
+      default:
+         break;
+     }
+
+   if (!interface)
+      ERR("failed to find interface for property \"%s\"", key);
+
+   return interface;
+}
+
+static void
+_e_connman_element_item_register(const char *key, const char *item)
+{
+   E_Connman_Element *element;
+   const char *interface;
+
+   interface = _e_connman_element_get_interface(key);
+   if (!interface)
+      return;
+
+   element = e_connman_element_register(item, interface);
+   if ((element) && (!e_connman_element_properties_sync(element)))
+      WRN("could not get properties of %s", element->path);
+}
+
+/* Match 2 arrays to find which are new and which are old elements
+ * For new elements, register them under prop_name property
+ * For old elements, unregister them, sending proper DEL event
+ */
+static void
+_e_connman_element_array_match(E_Connman_Array *old, E_Connman_Array *new, const char *prop_name)
+{
+   Eina_List *deleted = NULL;
+   Eina_Array_Iterator iter_old, iter_new;
+   unsigned int i_old = 0, i_new = 0;
+   void *item_old, *item_new;
+   Eina_List *l;
+   void *data;
+
+   if (!old)
+      return;
+
+   if (old->type != DBUS_TYPE_OBJECT_PATH)
+      return;
+
+   if ((!new) || (!new->array) || eina_array_count(new->array) == 0)
+     {
+        if ((!old) || (!old->array) || eina_array_count(old->array) == 0)
+          {
+             return;
+          }
+        else
+          {
+             iter_old = old->array->data;
+             goto out_remove_remaining;
+          }
+     }
+
+   iter_new = new->array->data;
+   item_new = *iter_new;
+   EINA_ARRAY_ITER_NEXT(old->array, i_old, item_old, iter_old)
+   {
+      if (item_old == item_new)
+        {
+           i_new++;
+           if (i_new >= eina_array_count(new->array))
+             {
+                i_old++;
+                break;
+             }
+
+           iter_new++;
+           item_new = *iter_new;
+        }
+      else
+        {
+           deleted = eina_list_append(deleted, item_old);
+        }
+   }
+
+   for(; i_new < eina_array_count(new->array); iter_new++, i_new++)
+     {
+        Eina_Bool found = EINA_FALSE;
+        item_new = *iter_new;
+        if (!item_new)
+           break;
+
+        EINA_LIST_FOREACH(deleted, l, data)
+        {
+           if (data == item_new)
+             {
+                deleted = eina_list_remove_list(deleted, l);
+                found = EINA_TRUE;
+                break;
+             }
+        }
+        if (!found)
+          {
+             _e_connman_element_item_register(prop_name, item_new);
+             DBG("Add element %s\n", (const char *)item_new);
+          }
+     }
+
+   /* everybody after i_old on old->array + everybody from deleted list
+      will be removed
+    */
+   EINA_LIST_FREE(deleted, data)
+   {
+      E_Connman_Element *e = e_connman_element_get(data);
+      if (e)
+         e_connman_element_unregister(e);
+
+      DBG("Delete element %s\n", (const char *)data);
+   }
+
+out_remove_remaining:
+   for(; i_old < eina_array_count(old->array); iter_old++, i_old++)
+     {
+        E_Connman_Element *e;
+        item_old = *iter_old;
+        if (!item_old)
+           break;
+
+        e = e_connman_element_get(item_old);
+        if (e)
+           e_connman_element_unregister(e);
+
+        DBG("Delete element %s\n", (const char *)item_old);
+     }
+}
+
+static Eina_Bool
+_e_connman_element_property_update(E_Connman_Element_Property *property, int type, void *data)
+{
+   Eina_Bool changed = EINA_FALSE;
+
+   if ((type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) && data)
+      data = (char *)eina_stringshare_add(data);
+
+   if (property->type != type)
+     {
+        if (property->type)
+           DBG("property type changed from '%c' to '%c'",
+               property->type, type);
+
+        _e_connman_element_property_value_free(property);
+        memset(&property->value, 0, sizeof(property->value));
+        property->type = type;
+        changed = EINA_TRUE;
+     }
+
+   switch (type)
+     {
+      case DBUS_TYPE_BOOLEAN:
+         if (changed || property->value.boolean != (Eina_Bool)(long)data)
+           {
+              property->value.boolean = (Eina_Bool)(long)data;
+              changed = EINA_TRUE;
+           }
+
+         break;
+
+      case DBUS_TYPE_BYTE:
+         if (changed || property->value.byte != (unsigned char)(long)data)
+           {
+              property->value.byte = (unsigned char)(long)data;
+              changed = EINA_TRUE;
+           }
+
+         break;
+
+      case DBUS_TYPE_UINT16:
+         if (changed || property->value.u16 != (unsigned short)(long)data)
+           {
+              property->value.u16 = (unsigned short)(long)data;
+              changed = EINA_TRUE;
+           }
+
+         break;
+
+      case DBUS_TYPE_UINT32:
+         if (changed || property->value.u32 != (unsigned int)(long)data)
+           {
+              property->value.u32 = (unsigned int)(long)data;
+              changed = EINA_TRUE;
+           }
+
+         break;
+
+      case DBUS_TYPE_STRING:
+         if (changed)
+           {
+              property->value.str = data;
+           }
+         else
+           {
+              if (property->value.str)
+                 eina_stringshare_del(property->value.str);
+
+              if (property->value.str != data)
+                {
+                   property->value.str = data;
+                   changed = EINA_TRUE;
+                }
+           }
+
+         break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+         if (changed)
+           {
+              property->value.path = data;
+           }
+         else
+           {
+              if (property->value.path)
+                 eina_stringshare_del(property->value.path);
+
+              if (property->value.path != data)
+                {
+                   property->value.path = data;
+                   changed = EINA_TRUE;
+                }
+           }
+
+         break;
+
+      case DBUS_TYPE_ARRAY:
+         if (!changed)
+            if (property->value.array)
+              {
+                 _e_connman_element_array_match(property->value.array, data, property->name);
+                 _e_connman_element_array_free(property->value.array, data);
+              }
+
+         property->value.array = data;
+         changed = EINA_TRUE;
+         break;
+
+      default:
+         ERR("don't know how to update property type %c (%d)", type, type);
+     }
+
+   return changed;
+}
+
+static E_Connman_Element_Property *
+_e_connman_element_property_new(const char *name, int type, void *data)
+{
+   E_Connman_Element_Property *property;
+
+   property = calloc(1, sizeof(*property));
+   if (!property)
+     {
+        eina_stringshare_del(name);
+        ERR("could not allocate property: %s", strerror(errno));
+        return NULL;
+     }
+
+   property->name = name;
+   _e_connman_element_property_update(property, type, data);
+   return property;
+}
+
+static void
+_e_connman_element_property_free(E_Connman_Element_Property *property)
+{
+   _e_connman_element_property_value_free(property);
+   eina_stringshare_del(property->name);
+   free(property);
+}
+
+/***********************************************************************
+* Element
+***********************************************************************/
+unsigned char *
+e_connman_element_bytes_array_get_stringshared(const E_Connman_Element *element, const char *property, unsigned int *count)
+{
+   Eina_Array_Iterator iterator;
+   E_Connman_Array *array;
+   unsigned char *ret, *p;
+   unsigned int i;
+   void *item;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(property, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, NULL);
+
+   *count = 0;
+
+   if (!e_connman_element_property_get_stringshared
+          (element, property, NULL, &array))
+      return NULL;
+
+   if ((!array) || (!(array->array)))
+      return NULL;
+
+   *count = eina_array_count(array->array);
+   ret = malloc(*count * sizeof(unsigned char));
+   if (!ret)
+     {
+        ERR("could not allocate return array of %d bytes: %s",
+            *count, strerror(errno));
+        return NULL;
+     }
+
+   p = ret;
+
+   EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+   {
+      *p = (unsigned char)(long)item;
+      p++;
+   }
+   return ret;
+}
+
+Eina_Bool
+e_connman_element_objects_array_get_stringshared(const E_Connman_Element *element, const char *property, unsigned int *count, E_Connman_Element ***p_elements)
+{
+   E_Connman_Element **ret, **p;
+   Eina_Array_Iterator iterator;
+   E_Connman_Array *array;
+   unsigned int i;
+   int type;
+   void *item;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(property, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
+
+   *count = 0;
+   *p_elements = NULL;
+
+   if (!e_connman_element_property_get_stringshared
+          (element, property, &type, &array))
+      return EINA_FALSE;
+
+   if (type != DBUS_TYPE_ARRAY)
+     {
+        ERR("property %s is not an array!", property);
+        return EINA_FALSE;
+     }
+
+   if ((!array) || (!array->array) || (array->type == DBUS_TYPE_INVALID))
+      return EINA_FALSE;
+
+   if (array->type != DBUS_TYPE_OBJECT_PATH)
+     {
+        ERR("property %s is not an array of object paths!", property);
+        return EINA_FALSE;
+     }
+
+   *count = eina_array_count(array->array);
+   ret = malloc(*count * sizeof(E_Connman_Element *));
+   if (!ret)
+     {
+        ERR("could not allocate return array of %d elements: %s",
+            *count, strerror(errno));
+        *count = 0;
+        return EINA_FALSE;
+     }
+
+   p = ret;
+
+   EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+   {
+      E_Connman_Element *e = e_connman_element_get(item);
+      if (!e)
+         continue;
+
+      *p = e;
+      p++;
+   }
+   *count = p - ret;
+   *p_elements = ret;
+   return EINA_TRUE;
+}
+
+/* array and strings are just pointers (references),
+ * no malloc, strdup or stringshare_add/ref
+ */
+Eina_Bool
+e_connman_element_strings_array_get_stringshared(const E_Connman_Element *element, const char *property, unsigned int *count, const char ***strings)
+{
+   E_Connman_Array *array;
+   int type;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(property, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(strings, EINA_FALSE);
+
+   *count = 0;
+   *strings = NULL;
+
+   if (!e_connman_element_property_get_stringshared
+          (element, property, &type, &array))
+      return EINA_FALSE;
+
+   if (type != DBUS_TYPE_ARRAY)
+     {
+        ERR("property %s is not an array!", property);
+        return EINA_FALSE;
+     }
+
+   if ((!array) || (!array->array) || (array->type == DBUS_TYPE_INVALID))
+      return EINA_FALSE;
+
+   if (array->type != DBUS_TYPE_STRING)
+     {
+        ERR("property %s is not an array of strings!", property);
+        return EINA_FALSE;
+     }
+
+   *count = array->array->count;
+   *strings = (const char **)array->array->data;
+   return EINA_TRUE;
+}
+
+static void
+_e_connman_element_array_print(FILE *fp, E_Connman_Array *array)
+{
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+   void *item;
+
+   if (!array)
+      return;
+
+   switch (array->type)
+     {
+      case DBUS_TYPE_OBJECT_PATH:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "\"%s\", ", (const char *)item);
+         break;
+
+      case DBUS_TYPE_STRING:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "\"%s\", ", (const char *)item);
+         break;
+
+      case DBUS_TYPE_BYTE:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "%#02hhx (\"%c\"), ", (unsigned char)(long)item,
+                 (unsigned char)(long)item);
+         break;
+
+      case DBUS_TYPE_UINT16:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "%#04hx (%hu), ", (unsigned short)(long)item,
+                 (unsigned short)(long)item);
+         break;
+
+      case DBUS_TYPE_UINT32:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "%#08x (%u), ", (unsigned int)(long)item,
+                 (unsigned int)(long)item);
+         break;
+
+      case DBUS_TYPE_DICT_ENTRY:
+         fputs("{ ", fp);
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         {
+            E_Connman_Element_Dict_Entry *entry = item;
+            fprintf(fp, "%s: ", entry->name);
+            switch (entry->type)
+              {
+               case DBUS_TYPE_OBJECT_PATH:
+                  fprintf(fp, "\"%s\", ", entry->value.path);
+                  break;
+
+               case DBUS_TYPE_STRING:
+                  fprintf(fp, "\"%s\", ", entry->value.str);
+                  break;
+
+               case DBUS_TYPE_BYTE:
+                  fprintf(fp, "%#02hhx (\"%c\"), ",
+                          entry->value.byte, entry->value.byte);
+                  break;
+
+               case DBUS_TYPE_UINT16:
+                  fprintf(fp, "%#04hx (%hu), ",
+                          entry->value.u16, entry->value.u16);
+                  break;
+
+               case DBUS_TYPE_UINT32:
+                  fprintf(fp, "%#08x (%u), ",
+                          entry->value.u32, entry->value.u32);
+                  break;
+
+               default:
+                  fprintf(fp, "<UNKNOWN TYPE '%c'>", entry->type);
+              }
+         }
+         fputs("}", fp);
+         break;
+
+      default:
+         fprintf(fp, "<UNKNOWN ARRAY TYPE '%c'>", array->type);
+     }
+}
+
+/**
+ * Print element to file descriptor.
+ */
+void
+e_connman_element_print(FILE *fp, const E_Connman_Element *element)
+{
+   const E_Connman_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN(fp);
+   if (!element)
+     {
+        fputs("Error: no element to print\n", fp);
+        return;
+     }
+
+   fprintf(fp,
+           "Element %p: %s [%s]\n"
+           "\tProperties:\n",
+           element, element->path, element->interface);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      fprintf(fp, "\t\t%s (%c) = ", p->name, p->type);
+
+      switch (p->type)
+        {
+         case DBUS_TYPE_STRING:
+            fprintf(fp, "\"%s\"", p->value.str);
+            break;
+
+         case DBUS_TYPE_OBJECT_PATH:
+            fprintf(fp, "\"%s\"", p->value.path);
+            break;
+
+         case DBUS_TYPE_BOOLEAN:
+            fprintf(fp, "%hhu", p->value.boolean);
+            break;
+
+         case DBUS_TYPE_BYTE:
+            fprintf(fp, "%#02hhx (%d), ", p->value.byte, p->value.byte);
+            break;
+
+         case DBUS_TYPE_UINT16:
+            fprintf(fp, "%hu", p->value.u16);
+            break;
+
+         case DBUS_TYPE_UINT32:
+            fprintf(fp, "%u", p->value.u32);
+            break;
+
+         case DBUS_TYPE_ARRAY:
+            _e_connman_element_array_print(fp, p->value.array);
+            break;
+
+         default:
+            fputs("don't know how to print type", fp);
+        }
+
+      fputc('\n', fp);
+   }
+}
+
+static E_Connman_Element *
+e_connman_element_new(const char *path, const char *interface)
+{
+   E_Connman_Element *element;
+
+   element = calloc(1, sizeof(*element));
+   if (!element)
+     {
+        ERR("could not allocate element: %s",   strerror(errno));
+        return NULL;
+     }
+
+   element->path = eina_stringshare_add(path);
+   element->interface = eina_stringshare_ref(interface);
+   element->_references = 1;
+
+   return element;
+}
+
+static void
+e_connman_element_extra_properties_free(E_Connman_Element *element)
+{
+   while (element->props)
+     {
+        E_Connman_Element_Property *prop;
+        prop = (E_Connman_Element_Property *)element->props;
+        element->props = element->props->next;
+        _e_connman_element_property_free(prop);
+     }
+}
+
+static void
+e_connman_element_free(E_Connman_Element *element)
+{
+   if (element->_idler.changed)
+      ecore_idler_del(element->_idler.changed);
+
+   while (element->_listeners)
+     {
+        E_Connman_Element_Listener *l = (void *)element->_listeners;
+        element->_listeners = eina_inlist_remove
+              (element->_listeners, element->_listeners);
+
+        if (l->free_data)
+           l->free_data(l->data);
+
+        free(l);
+     }
+
+   e_connman_element_pending_cancel_and_free(&element->_pending.properties_get);
+   e_connman_element_pending_cancel_and_free(&element->_pending.property_set);
+   e_connman_element_pending_cancel_and_free(&element->_pending.agent_register);
+   e_connman_element_pending_cancel_and_free(&element->_pending.agent_unregister);
+   e_connman_element_pending_cancel_and_free(&element->_pending.request_scan);
+   e_connman_element_pending_cancel_and_free(&element->_pending.technology_enable);
+   e_connman_element_pending_cancel_and_free(&element->_pending.technology_disable);
+   e_connman_element_pending_cancel_and_free(&element->_pending.profile_remove);
+   e_connman_element_pending_cancel_and_free(&element->_pending.service_connect);
+   e_connman_element_pending_cancel_and_free(&element->_pending.service_disconnect);
+   e_connman_element_pending_cancel_and_free(&element->_pending.service_remove);
+   e_connman_element_pending_cancel_and_free(&element->_pending.service_move_before);
+   e_connman_element_pending_cancel_and_free(&element->_pending.service_move_after);
+   e_connman_element_pending_cancel_and_free(&element->_pending.service_clear_property);
+
+   e_connman_element_extra_properties_free(element);
+   eina_stringshare_del(element->interface);
+   eina_stringshare_del(element->path);
+   free(element);
+}
+
+/**
+ * Add reference to element.
+ */
+int
+e_connman_element_ref(E_Connman_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, 0);
+   return ++element->_references;
+}
+
+/**
+ * Remove reference from element.
+ *
+ * If reference count drops to 0 element will be freed.
+ */
+int
+e_connman_element_unref(E_Connman_Element *element)
+{
+   int i;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, 0);
+
+   i = --element->_references;
+   if (i == 0)
+      e_connman_element_free(element);
+   else if (i < 0)
+      ERR("element %p references %d < 0", element, i);
+
+   return i;
+}
+
+/**
+ * Send message with callbacks set to work with connman elements.
+ *
+ * If this call fails (returns @c EINA_FALSE), pending callbacks will not be called,
+ * not even with error messages.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
+ */
+Eina_Bool
+e_connman_element_message_send(E_Connman_Element *element, const char *method_name, E_DBus_Method_Return_Cb cb, DBusMessage *msg, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
+{
+   E_Connman_Element_Call_Data *data;
+   E_Connman_Element_Pending *p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(msg, EINA_FALSE);
+
+   data = malloc(sizeof(*data));
+   if (!data)
+     {
+        ERR("could not alloc e_connman_element_call_data: %s",
+            strerror(errno));
+        dbus_message_unref(msg);
+        return EINA_FALSE;
+     }
+
+   p = malloc(sizeof(*p));
+   if (!p)
+     {
+        ERR("could not alloc E_Connman_Element_Pending: %s",
+            strerror(errno));
+        free(data);
+        dbus_message_unref(msg);
+        return EINA_FALSE;
+     }
+
+   data->element = element;
+   data->cb = cb;
+   data->pending = p;
+   data->p_list = pending;
+   p->user_cb = user_cb;
+   p->user_data = (void *)user_data;
+   p->data = data;
+   p->pending = e_dbus_message_send
+         (e_connman_conn, msg, e_connman_element_call_dispatch_and_free, -1, data);
+   dbus_message_unref(msg);
+
+   if (p->pending)
+     {
+        *pending = eina_inlist_append(*pending, EINA_INLIST_GET(p));
+        return EINA_TRUE;
+     }
+
+   ERR("failed to call %s (obj=%s, path=%s, iface=%s)",
+       method_name, e_connman_system_bus_name_get(),
+       element->path, element->interface);
+   free(data);
+   free(p);
+   return EINA_FALSE;
+}
+
+Eina_Bool
+e_connman_element_call_full(E_Connman_Element *element, const char *method_name, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
+{
+   DBusMessage *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_connman_system_bus_name_get(), element->path, element->interface,
+         method_name);
+
+   return e_connman_element_message_send
+             (element, method_name, cb, msg, pending, user_cb, user_data);
+}
+
+static Eina_Bool
+_e_connman_element_property_value_add(E_Connman_Element *element, const char *name, int type, void *value)
+{
+   E_Connman_Element_Property *p;
+
+   name = eina_stringshare_add(name);
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      if (p->name == name)
+        {
+           eina_stringshare_del(name);
+           return _e_connman_element_property_update(p, type, value);
+        }
+   }
+
+   p = _e_connman_element_property_new(name, type, value);
+   if (!p)
+     {
+        ERR("could not create property %s (%c)", name, type);
+        return EINA_FALSE;
+     }
+
+   element->props = eina_inlist_append(element->props, EINA_INLIST_GET(p));
+   return EINA_TRUE;
+}
+
+static E_Connman_Array *
+_e_connman_element_iter_get_array(DBusMessageIter *itr, const char *key)
+{
+   E_Connman_Array *array;
+   DBusMessageIter e_itr;
+
+   array = malloc(sizeof(E_Connman_Array));
+   if (!array)
+     {
+        ERR("could not create new e_connman array.");
+        return NULL;
+     }
+
+   array->array = eina_array_new(16);
+   if (!(array->array))
+     {
+        ERR("could not create new eina array.");
+        free(array);
+        return NULL;
+     }
+
+   dbus_message_iter_recurse(itr, &e_itr);
+   array->type = dbus_message_iter_get_arg_type(&e_itr);
+   if (array->type == DBUS_TYPE_INVALID)
+     {
+        DBG("array %s is of type 'invalid' (empty?)", key);
+        eina_array_free(array->array);
+        free(array);
+        return NULL;
+     }
+
+   do
+     {
+        switch (array->type)
+          {
+           case DBUS_TYPE_OBJECT_PATH:
+           {
+              const char *path;
+
+              dbus_message_iter_get_basic(&e_itr, &path);
+              path = eina_stringshare_add(path);
+              eina_array_push(array->array, path);
+              _e_connman_element_item_register(key, path);
+           }
+           break;
+
+           case DBUS_TYPE_STRING:
+           {
+              const char *str;
+
+              dbus_message_iter_get_basic(&e_itr, &str);
+              str = eina_stringshare_add(str);
+              eina_array_push(array->array, str);
+           }
+           break;
+
+           case DBUS_TYPE_BYTE:
+           {
+              unsigned char byte;
+              dbus_message_iter_get_basic(&e_itr, &byte);
+              eina_array_push(array->array, (void *)(long)byte);
+           }
+           break;
+
+           case DBUS_TYPE_DICT_ENTRY:
+           {
+              E_Connman_Element_Dict_Entry *entry;
+              entry = _e_connman_element_dict_entry_new(&e_itr);
+              if (entry)
+                 eina_array_push(array->array, entry);
+           }
+           break;
+
+           default:
+              ERR("don't know how to build array '%s' of type %c (%d)",
+                  key, array->type, array->type);
+              eina_array_free(array->array);
+              free(array);
+              return NULL;
+          }
+     }
+   while (dbus_message_iter_next(&e_itr));
+   return array;
+}
+
+static void
+_e_connman_element_get_properties_callback(void *user_data, DBusMessage *msg, DBusError *err)
+{
+   E_Connman_Element *element = user_data;
+   DBusMessageIter itr, s_itr;
+   int t, changed;
+
+   DBG("get_properties msg=%p", msg);
+
+   if (!_dbus_callback_check_and_init(msg, &itr, err))
+      return;
+
+   t = dbus_message_iter_get_arg_type(&itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_ARRAY))
+      return;
+
+   changed = 0;
+   dbus_message_iter_recurse(&itr, &s_itr);
+   do
+     {
+        DBusMessageIter e_itr, v_itr;
+        const char *key;
+        void *value = NULL;
+        int r;
+
+        t = dbus_message_iter_get_arg_type(&s_itr);
+        if (!_dbus_iter_type_check(t, DBUS_TYPE_DICT_ENTRY))
+           continue;
+
+        dbus_message_iter_recurse(&s_itr, &e_itr);
+
+        t = dbus_message_iter_get_arg_type(&e_itr);
+        if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
+           continue;
+
+        dbus_message_iter_get_basic(&e_itr, &key);
+        dbus_message_iter_next(&e_itr);
+        t = dbus_message_iter_get_arg_type(&e_itr);
+        if (!_dbus_iter_type_check(t, DBUS_TYPE_VARIANT))
+           continue;
+
+        dbus_message_iter_recurse(&e_itr, &v_itr);
+        t = dbus_message_iter_get_arg_type(&v_itr);
+        if (t == DBUS_TYPE_ARRAY)
+          {
+             value = _e_connman_element_iter_get_array(&v_itr, key);
+          }
+        else if (t != DBUS_TYPE_INVALID)
+          {
+             dbus_message_iter_get_basic(&v_itr, &value);
+          }
+        else
+          {
+             ERR("property has invalid type %s", key);
+             continue;
+          }
+
+        r = _e_connman_element_property_value_add(element, key, t, value);
+        if (r < 0)
+          {
+             ERR("failed to add property value %s (%c)", key, t);
+          }
+        else if (r == 1)
+          {
+             INF("property value changed %s (%c)", key, t);
+             changed = 1;
+          }
+     }
+   while (dbus_message_iter_next(&s_itr));
+
+   if (changed)
+      _e_connman_element_listeners_call(element);
+}
+
+/**
+ * Sync element properties with server.
+ *
+ * Call method GetProperties() at the given element on server in order to sync
+ * them.
+ *
+ * @param element to call method on server.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_element_sync_properties_full(E_Connman_Element *element, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "GetProperties";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return e_connman_element_call_full
+             (element, name, _e_connman_element_get_properties_callback,
+             &element->_pending.properties_get, cb, data);
+}
+
+/**
+ * Sync element properties with server, simple version.
+ *
+ * Call method GetProperties() at the given element on server in order to sync
+ * them. This is the simple version and there is no check of server reply
+ * for errors.
+ *
+ * @param element to call method on server.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_element_properties_sync(E_Connman_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return e_connman_element_sync_properties_full(element, NULL, NULL);
+}
+
+/**
+ * Call method SetProperty(prop, {key: value}) at the given element on server.
+ *
+ * This is a server call, not local, so it may fail and in that case
+ * no property is updated locally. If the value was set the event
+ * E_CONNMAN_EVENT_ELEMENT_UPDATED will be added to main loop.
+ *
+ * @param element to call method on server.
+ * @param prop property name.
+ * @param key dict key name.
+ * @param type DBus type to use for value.
+ * @param value pointer to value, just like regular DBus, see
+ *        dbus_message_iter_append_basic().
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_element_property_dict_set_full(E_Connman_Element *element, const char *prop, const char *key, int type, const void *value, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "SetProperty";
+   DBusMessage *msg;
+   DBusMessageIter itr, variant, dict, entry;
+   char typestr[32];
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_connman_system_bus_name_get(), element->path, element->interface, name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &prop);
+
+   if ((size_t)snprintf(typestr, sizeof(typestr),
+                        (DBUS_TYPE_ARRAY_AS_STRING
+                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                         DBUS_TYPE_STRING_AS_STRING
+                         "%c"
+                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
+                        type) >= sizeof(typestr))
+     {
+        ERR("sizeof(typestr) is too small!");
+        return EINA_FALSE;
+     }
+
+   if (dbus_message_iter_open_container(&itr, DBUS_TYPE_VARIANT, typestr, &variant))
+     {
+        snprintf(typestr, sizeof(typestr),
+                 (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                     DBUS_TYPE_STRING_AS_STRING
+                     "%c"
+                     DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
+                 type);
+        if (dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, typestr, &dict))
+          {
+             if (dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry))
+               {
+                  dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+                  if ((type == DBUS_TYPE_STRING) || (type == DBUS_TYPE_OBJECT_PATH))
+                    dbus_message_iter_append_basic(&entry, type, &value);
+                  else
+                    dbus_message_iter_append_basic(&entry, type, value);
+                  
+                  dbus_message_iter_close_container(&dict, &entry);
+               }
+             else
+               {
+                  ERR("dbus_message_iter_open_container() failed");
+               }
+             dbus_message_iter_close_container(&variant, &dict);
+          }
+        else
+          {
+             ERR("dbus_message_iter_open_container() failed");
+          }
+        dbus_message_iter_close_container(&itr, &variant);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+
+   return e_connman_element_message_send
+             (element, name, NULL, msg, &element->_pending.property_set, cb, data);
+}
+
+/**
+ * Call method SetProperty(prop, value) at the given element on server.
+ *
+ * This is a server call, not local, so it may fail and in that case
+ * no property is updated locally. If the value was set the event
+ * E_CONNMAN_EVENT_ELEMENT_UPDATED will be added to main loop.
+ *
+ * @param element to call method on server.
+ * @param prop property name.
+ * @param type DBus type to use for value.
+ * @param value pointer to value, just like regular DBus, see
+ *        dbus_message_iter_append_basic().
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_element_property_set_full(E_Connman_Element *element, const char *prop, int type, const void *value, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "SetProperty";
+   char typestr[2];
+   DBusMessage *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_connman_system_bus_name_get(), element->path, element->interface, name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   DBusMessageIter itr, v;
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &prop);
+
+   typestr[0] = type;
+   typestr[1] = '\0';
+   if (dbus_message_iter_open_container(&itr, DBUS_TYPE_VARIANT, typestr, &v))
+     {
+        if ((type == DBUS_TYPE_STRING) || (type == DBUS_TYPE_OBJECT_PATH))
+          {
+             dbus_message_iter_append_basic(&v, type, &value);
+          }
+        else if (type == DBUS_TYPE_BOOLEAN)
+          {
+             unsigned int b = *(char *)value;
+             dbus_message_iter_append_basic(&v, type, &b);
+          }
+        else
+          {
+             dbus_message_iter_append_basic(&v, type, value);
+          }
+        
+        dbus_message_iter_close_container(&itr, &v);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+
+   return e_connman_element_message_send
+             (element, name, NULL, msg, &element->_pending.property_set, cb, data);
+}
+
+/**
+ * Call method SetProperty(prop, value) at the given element on server, when
+ * value is an array.
+ *
+ * This is a server call, not local, so it may fail and in that case
+ * no property is updated locally. If the value was set the event
+ * E_CONNMAN_EVENT_ELEMENT_UPDATED will be added to main loop.
+ *
+ * @param element to call method on server.
+ * @param prop property name.
+ * @param type DBus type to use for value.
+ * @param value pointer to value, just like regular DBus, see
+ *        dbus_message_iter_append_basic().
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_element_property_array_set_full(E_Connman_Element *element, const char *prop, int type, unsigned int count, const void * const *values, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "SetProperty";
+   char type_sig[2] = { type, '\0'};
+   char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' };
+   DBusMessage *msg;
+   DBusMessageIter itr, variant, array;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_connman_system_bus_name_get(), element->path, element->interface, name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &prop);
+
+   if (dbus_message_iter_open_container(&itr, DBUS_TYPE_VARIANT, array_sig, &variant))
+     {
+        if (dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, type_sig, &array))
+          {
+             if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH)
+               {
+                  unsigned int i;
+                  for (i = 0; i < count; i++)
+                    {
+                       const void *entry = values[i];
+                       dbus_message_iter_append_basic(&array, type, &entry);
+                    }
+               }
+             else
+               {
+                  unsigned int i;
+                  for (i = 0; i < count; i++)
+                    {
+                       const void *entry = values[i];
+                       dbus_message_iter_append_basic(&array, type, entry);
+                    }
+               }
+             
+             dbus_message_iter_close_container(&variant, &array);
+          }
+        else
+          {
+             ERR("dbus_message_iter_open_container() failed");
+          }
+        dbus_message_iter_close_container(&itr, &variant);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+   
+   return e_connman_element_message_send(element, name, NULL, msg,
+                                         &element->_pending.property_set,
+                                         cb, data);
+}
+
+/**
+ * Call method SetProperty(prop, value) at the given element on server.
+ *
+ * This is the simple version and there is no check of server reply
+ * for errors.
+ *
+ * @param element to call method on server.
+ * @param prop property name.
+ * @param type DBus type to use for value.
+ * @param value pointer to value, just like regular DBus, see
+ *        dbus_message_iter_append_basic().
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_element_property_set(E_Connman_Element *element, const char *prop, int type, const void *value)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
+   return e_connman_element_property_set_full
+             (element, prop, type, value, NULL, NULL);
+}
+
+Eina_Bool
+e_connman_element_call_with_path(E_Connman_Element *element, const char *method_name, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
+{
+   DBusMessageIter itr;
+   DBusMessage *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_connman_system_bus_name_get(), element->path, element->interface,
+         method_name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_OBJECT_PATH, &string);
+
+   return e_connman_element_message_send
+             (element, method_name, cb, msg, pending, user_cb, user_data);
+}
+
+Eina_Bool
+e_connman_element_call_with_string(E_Connman_Element *element, const char *method_name, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
+{
+   DBusMessageIter itr;
+   DBusMessage *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_connman_system_bus_name_get(), element->path, element->interface,
+         method_name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &string);
+
+   return e_connman_element_message_send
+             (element, method_name, cb, msg, pending, user_cb, user_data);
+}
+
+/**
+ * Get property type.
+ *
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param name property name, must be previously stringshared
+ * @param type will contain the value type.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_element_property_type_get_stringshared(const E_Connman_Element *element, const char *name, int *type)
+{
+   const E_Connman_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      if (p->name == name)
+        {
+           *type = p->type;
+           return EINA_TRUE;
+        }
+   }
+
+   WRN("element %s (%p) has no property with name \"%s\".",
+       element->path, element, name);
+   return EINA_FALSE;
+}
+
+/**
+ * Get property type.
+ *
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param name property name
+ * @param type will contain the value type.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_element_property_type_get(const E_Connman_Element *element, const char *name, int *type)
+{
+   Eina_Bool ret;
+   name = eina_stringshare_add(name);
+   ret = e_connman_element_property_type_get_stringshared(element, name, type);
+   eina_stringshare_del(name);
+   return ret;
+}
+
+void
+e_connman_element_list_properties(const E_Connman_Element *element, Eina_Bool (*cb)(void *data, const E_Connman_Element *element, const char *name, int type, const void *value), const void *data)
+{
+   const E_Connman_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN(element);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      const void *value = NULL;
+
+      switch (p->type)
+        {
+         case DBUS_TYPE_STRING:
+            value = &p->value.str;
+            break;
+
+         case DBUS_TYPE_OBJECT_PATH:
+            value = &p->value.path;
+            break;
+
+         case DBUS_TYPE_BOOLEAN:
+            value = (void *)&p->value.boolean;
+            break;
+
+         case DBUS_TYPE_UINT16:
+            value = &p->value.u16;
+            break;
+
+         case DBUS_TYPE_UINT32:
+            value = &p->value.u32;
+            break;
+
+         default:
+            ERR("unsupported type %c", p->type);
+        }
+
+      if (!cb((void *)data, element, p->name, p->type, value))
+         return;
+   }
+}
+
+/**
+ * Get dict value given its key inside a dict property.
+ *
+ * This will look into properties for one of type dict that contains
+ * the given key, to find the property.  If no property is found then
+ * @c EINA_FALSE is returned.
+ *
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param dict_name property name, must be previously stringshared
+ * @param key key inside dict, must be previously stringshared
+ * @param type if provided it will contain the value type.
+ * @param value where to store the property value, must be a pointer to the
+ *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_element_property_dict_get_stringshared(const E_Connman_Element *element, const char *dict_name, const char *key, int *type, void *value)
+{
+   const E_Connman_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dict_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      E_Connman_Element_Dict_Entry *entry;
+      E_Connman_Array *array;
+
+      if (p->name != dict_name)
+         continue;
+
+      if (p->type != DBUS_TYPE_ARRAY)
+        {
+           WRN("element %s (%p) has property \"%s\" is not an array: %c (%d)",
+               element->path, element, dict_name, p->type, p->type);
+           return EINA_FALSE;
+        }
+
+      array = p->value.array;
+      if ((!array) || (array->type != DBUS_TYPE_DICT_ENTRY))
+        {
+           int t = array ? array->type : DBUS_TYPE_INVALID;
+           WRN("element %s (%p) has property \"%s\" is not a dict: %c (%d)",
+               element->path, element, dict_name, t, t);
+           return EINA_FALSE;
+        }
+
+      entry = _e_connman_element_array_dict_find_stringshared(array, key);
+      if (!entry)
+        {
+           WRN("element %s (%p) has no dict property with name \"%s\" with "
+               "key \"%s\".",
+               element->path, element, dict_name, key);
+           return EINA_FALSE;
+        }
+
+      if (type)
+         *type = entry->type;
+
+      switch (entry->type)
+        {
+         case DBUS_TYPE_BOOLEAN:
+            *(Eina_Bool *)value = entry->value.boolean;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_BYTE:
+            *(unsigned char *)value = entry->value.byte;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_UINT16:
+            *(unsigned short *)value = entry->value.u16;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_UINT32:
+            *(unsigned int *)value = entry->value.u32;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_STRING:
+            *(const char **)value = entry->value.str;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_OBJECT_PATH:
+            *(const char **)value = entry->value.path;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_ARRAY:
+            *(E_Connman_Array **)value = entry->value.array;
+            return EINA_TRUE;
+
+         default:
+            ERR("don't know how to get property %s, key %s type %c (%d)",
+                dict_name, key, entry->type, entry->type);
+            return EINA_FALSE;
+        }
+   }
+
+   DBG("element %s (%p) has no property with name \"%s\".",
+       element->path, element, dict_name);
+   return EINA_FALSE;
+}
+
+Eina_Bool
+e_connman_element_property_dict_strings_array_get_stringshared(const E_Connman_Element *element, const char *dict_name, const char *key, unsigned int *count, const char ***strings)
+{
+   const char **ret, **p;
+   Eina_Array_Iterator iterator;
+   E_Connman_Array *array;
+   unsigned int i;
+   int type;
+   void *item;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dict_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(strings, EINA_FALSE);
+
+   *count = 0;
+   *strings = NULL;
+
+   if (!e_connman_element_property_dict_get_stringshared(element, dict_name,
+                                                         key, &type, &array))
+      return EINA_FALSE;
+
+   if (type != DBUS_TYPE_ARRAY)
+     {
+        ERR("property %s.%s is not an array!", dict_name, key);
+        return EINA_FALSE;
+     }
+
+   if ((!array) || (!array->array) || (array->type == DBUS_TYPE_INVALID))
+      return EINA_FALSE;
+
+   if (array->type != DBUS_TYPE_STRING)
+     {
+        ERR("property %s.%s is not an array of strings!", dict_name, key);
+        return EINA_FALSE;
+     }
+
+   *count = eina_array_count(array->array);
+   ret = malloc(*count * sizeof(char *));
+   if (!ret)
+     {
+        ERR("could not allocate return array of %d strings: %s",
+            *count, strerror(errno));
+        *count = 0;
+        return EINA_FALSE;
+     }
+
+   p = ret;
+
+   EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+     {
+        if (!item)
+           continue;
+
+        *p = item;
+        p++;
+     }
+   *count = p - ret;
+   *strings = ret;
+   return EINA_TRUE;
+}
+
+/**
+ * Get property value given its name.
+ *
+ * This will look into properties, to find the property.
+ * If no property is found then @c EINA_FALSE is returned.
+ *
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param name property name, must be previously stringshared
+ * @param type if provided it will contain the value type.
+ * @param value where to store the property value, must be a pointer to the
+ *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_element_property_get_stringshared(const E_Connman_Element *element, const char *name, int *type, void *value)
+{
+   const E_Connman_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      if (p->name != name)
+         continue;
+
+      if (type)
+         *type = p->type;
+
+      switch (p->type)
+        {
+         case DBUS_TYPE_BOOLEAN:
+            *(Eina_Bool *)value = p->value.boolean;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_BYTE:
+            *(unsigned char *)value = p->value.byte;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_UINT16:
+            *(unsigned short *)value = p->value.u16;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_UINT32:
+            *(unsigned int *)value = p->value.u32;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_STRING:
+            *(const char **)value = p->value.str;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_OBJECT_PATH:
+            *(const char **)value = p->value.path;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_ARRAY:
+            *(E_Connman_Array **)value = p->value.array;
+            return EINA_TRUE;
+
+         default:
+            ERR("don't know how to get property type %c (%d)",
+                p->type, p->type);
+            return EINA_FALSE;
+        }
+   }
+
+   WRN("element %s (%p) has no property with name \"%s\".",
+       element->path, element, name);
+   return EINA_FALSE;
+}
+
+/**
+ * Get property value given its name.
+ *
+ * This will look into properties, to find the property.
+ * If no property is found then @c EINA_FALSE is returned.
+ *
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param name property name
+ * @param type if provided it will contain the value type.
+ * @param value where to store the property value, must be a pointer to the
+ *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_element_property_get(const E_Connman_Element *element, const char *name, int *type, void *value)
+{
+   Eina_Bool ret;
+   name = eina_stringshare_add(name);
+   ret = e_connman_element_property_get_stringshared
+         (element, name, type, value);
+   eina_stringshare_del(name);
+   return ret;
+}
+
+struct e_connman_elements_for_each_data
+{
+   Eina_Hash_Foreach cb;
+   void             *data;
+};
+
+static Eina_Bool
+_e_connman_elements_for_each(Eina_Hash *hash __UNUSED__, const char *key, void *data, void *fdata)
+{
+   struct e_connman_elements_for_each_data *each_data = fdata;
+
+   each_data->cb(elements, key, data, each_data->data);
+   return EINA_TRUE;
+}
+
+/**
+ * Call the given function for each existing element.
+ *
+ * @param cb function to call for each element. It will get as parameters,
+ *        in order: the element pointer and the given @a user_data.
+ * @param user_data data to give to @a cb for each element.
+ */
+void
+e_connman_elements_for_each(Eina_Hash_Foreach cb, const void *user_data)
+{
+   struct e_connman_elements_for_each_data data = {cb, (void *)user_data};
+
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+
+   eina_hash_foreach(elements, (Eina_Hash_Foreach)_e_connman_elements_for_each,
+                     &data);
+}
+
+static Eina_Bool
+_e_connman_elements_get_allocate(unsigned int *count, E_Connman_Element ***p_elements)
+{
+   *count = eina_hash_population(elements);
+   if (*count == 0)
+     {
+        *p_elements = NULL;
+        return EINA_TRUE;
+     }
+
+   *p_elements = malloc(*count * sizeof(E_Connman_Element *));
+   if (!*p_elements)
+     {
+        ERR("could not allocate return array of %d elements: %s",
+            *count, strerror(errno));
+        *count = 0;
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_connman_elements_get_all(Eina_Hash *hash __UNUSED__, const char *key __UNUSED__, void *data, void *fdata)
+{
+   E_Connman_Element *element = data;
+   E_Connman_Element ***p_ret = fdata;
+
+   **p_ret = element;
+   (*p_ret)++;
+   return EINA_TRUE;
+}
+
+/**
+ * Get all known elements.
+ *
+ * No reference is added to these elements, since there are no threads
+ * in the system, you are free to add references yourself right after
+ * the return of this call without race condition, elements by the
+ * system (ie: elementRemoved signal)could only be touched on the next
+ * main loop iteration.
+ *
+ * @param count return the number of elements in array.
+ * @param p_elements array with all elements, these are not referenced
+ *        and in no particular order, just set if return is @c EINA_TRUE.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_elements_get_all(unsigned int *count, E_Connman_Element ***p_elements)
+{
+   E_Connman_Element **p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
+
+   if (!_e_connman_elements_get_allocate(count, p_elements))
+      return EINA_FALSE;
+
+   p = *p_elements;
+   eina_hash_foreach(elements, (Eina_Hash_Foreach)_e_connman_elements_get_all,
+                     &p);
+   return EINA_TRUE;
+}
+
+struct e_connman_elements_get_all_str_data
+{
+   E_Connman_Element **elements;
+   int                 count;
+   const char         *str;
+};
+
+static Eina_Bool
+_e_connman_elements_get_all_type(Eina_Hash *hash __UNUSED__, const char *key __UNUSED__, void *e, void *user_data)
+{
+   struct e_connman_elements_get_all_str_data *data = user_data;
+   E_Connman_Element *element = e;
+
+   if ((data->str) && (element->interface != data->str))
+      return EINA_TRUE;
+
+   data->elements[data->count] = element;
+   data->count++;
+   return EINA_TRUE;
+}
+
+/**
+ * Get all known elements of type.
+ *
+ * No reference is added to these elements, since there are no threads
+ * in the system, you are free to add references yourself right after
+ * the return of this call without race condition, elements by the
+ * system (ie: ElementRemoved signal) could only be touched on the next
+ * main loop iteration.
+ *
+ * @param type type to filter, or NULL to get all.
+ * @param count return the number of elements in array.
+ * @param p_elements array with all elements, these are not referenced
+ *        and in no particular order, just set if return is @c EINA_TRUE.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * @see e_connman_elements_get_all()
+ */
+Eina_Bool
+e_connman_elements_get_all_type(const char *type, unsigned int *count, E_Connman_Element ***p_elements)
+{
+   struct e_connman_elements_get_all_str_data data;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
+
+   if (!_e_connman_elements_get_allocate(count, p_elements))
+      return EINA_FALSE;
+
+   data.elements = *p_elements;
+   data.count = 0;
+   data.str = eina_stringshare_add(type);
+   eina_hash_foreach(elements,
+                     (Eina_Hash_Foreach)_e_connman_elements_get_all_type,
+                     &data);
+
+   eina_stringshare_del(data.str);
+   *count = data.count;
+   return EINA_TRUE;
+}
+
+/**
+ * Get the element registered at given path.
+ *
+ * @param path the path to query for registered object.
+ *
+ * @return element pointer if found, NULL otherwise. No references are added.
+ */
+E_Connman_Element *
+e_connman_element_get(const char *path)
+{
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+   element = eina_hash_find(elements, path);
+
+   return element;
+}
+
+static void
+_e_connman_element_property_changed_callback(void *data, DBusMessage *msg)
+{
+   E_Connman_Element *element = (E_Connman_Element *)data;
+   DBusMessageIter itr, v_itr;
+   int t, r, changed = 0;
+   const char *name = NULL;
+   void *value = NULL;
+
+   DBG("Property changed in element %s", element->path);
+
+   if (!_dbus_callback_check_and_init(msg, &itr, NULL))
+      return;
+
+   t = dbus_message_iter_get_arg_type(&itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
+     {
+        ERR("missing name in property changed signal");
+        return;
+     }
+
+   dbus_message_iter_get_basic(&itr, &name);
+
+   dbus_message_iter_next(&itr);
+   t = dbus_message_iter_get_arg_type(&itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_VARIANT))
+     {
+        ERR("missing value in property changed signal");
+        return;
+     }
+
+   dbus_message_iter_recurse(&itr, &v_itr);
+   t = dbus_message_iter_get_arg_type(&v_itr);
+
+   if (t == DBUS_TYPE_ARRAY)
+     {
+        value = _e_connman_element_iter_get_array(&v_itr, name);
+     }
+   else if (t != DBUS_TYPE_INVALID)
+     {
+        dbus_message_iter_get_basic(&v_itr, &value);
+     }
+   else
+     {
+        ERR("property has invalid type %s", name);
+        return;
+     }
+
+   r = _e_connman_element_property_value_add(element, name, t, value);
+   if (r < 0)
+     {
+        ERR("failed to add property value %s (%c)", name, t);
+     }
+   else if (r == 1)
+     {
+        INF("property value changed %s (%c)", name, t);
+        changed = 1;
+     }
+
+   if (changed)
+      _e_connman_element_listeners_call(element);
+}
+
+/**
+ * Register the given path, possible creating and element and return it.
+ *
+ * This will check if path is already registered, in that case the
+ * exiting element is returned. If it was not registered yet, a new
+ * element is created, registered and returned.
+ *
+ * This call will not add extra references to the object.
+ *
+ * @param path the path to register the element
+ *
+ * @return the registered object, no references are added.
+ */
+E_Connman_Element *
+e_connman_element_register(const char *path, const char *interface)
+{
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(interface, NULL);
+
+   element = eina_hash_find(elements, path);
+   if (element)
+      return element;
+
+   element = e_connman_element_new(path, interface);
+   if (!element)
+      return NULL;
+
+   if (!eina_hash_add(elements, element->path, element))
+     {
+        ERR("could not add element %s to hash, delete it.", path);
+        e_connman_element_free(element);
+        return NULL;
+     }
+
+   element->signal_handler =
+      e_dbus_signal_handler_add
+         (e_connman_conn, e_connman_system_bus_name_get(),
+         element->path, element->interface, "PropertyChanged",
+         _e_connman_element_property_changed_callback, element);
+
+   e_connman_element_event_add(E_CONNMAN_EVENT_ELEMENT_ADD, element);
+
+   return element;
+}
+
+static void
+_e_connman_element_event_unregister_and_free(void *data __UNUSED__, void *ev)
+{
+   E_Connman_Element *element = ev;
+   e_connman_element_unref(element);
+}
+
+static void
+_e_connman_element_unregister_internal(E_Connman_Element *element)
+{
+   if (element->signal_handler)
+     {
+        e_dbus_signal_handler_del(e_connman_conn, element->signal_handler);
+        element->signal_handler = NULL;
+     }
+
+   ecore_event_add(E_CONNMAN_EVENT_ELEMENT_DEL, element,
+                   _e_connman_element_event_unregister_and_free, NULL);
+}
+
+/**
+ * Forget about the given element.
+ *
+ * This will remove the element from the pool of known objects, then
+ * add an E_CONNMAN_EVENT_ELEMENT_DEL and after that will unreference it,
+ * possible freeing it.
+ *
+ * @param element element to forget about. Its reference will be removed.
+ */
+void
+e_connman_element_unregister(E_Connman_Element *element)
+{
+   if (!element)
+      return;
+
+   if (elements)
+      eina_hash_del_by_key(elements, element->path);
+}
+
+/**
+ * Remove all known elements.
+ *
+ * This will remove all known elements but will NOT add any
+ * E_CONNMAN_EVENT_ELEMENT_DEL to main loop.
+ *
+ * This is just useful to make sure next e_connman_manager_sync_elements()
+ * will not leave any stale elements. This is unlikely to happen, as
+ * E_Connman is supposed to catch all required events to avoid stale elements.
+ */
+void
+e_connman_manager_clear_elements(void)
+{
+   e_connman_elements_shutdown();
+   e_connman_elements_init();
+}
+
+/**
+ * Creates elements hash.
+ *
+ * This has no init counter since its already guarded by other code.
+ * @internal
+ */
+void
+e_connman_elements_init(void)
+{
+   EINA_SAFETY_ON_FALSE_RETURN(!elements);
+   elements =
+      eina_hash_string_superfast_new(EINA_FREE_CB
+                                        (_e_connman_element_unregister_internal));
+}
+
+void
+e_connman_elements_shutdown(void)
+{
+   EINA_SAFETY_ON_FALSE_RETURN(!!elements);
+   eina_hash_free(elements);
+   elements = NULL;
+}
+
+static inline Eina_Bool
+_e_connman_element_is(const E_Connman_Element *element, const char *interface)
+{
+   return element->interface == interface;
+}
+
+Eina_Bool
+e_connman_element_is_manager(const E_Connman_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return _e_connman_element_is(element, e_connman_iface_manager);
+}
+
+Eina_Bool
+e_connman_element_is_profile(const E_Connman_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return _e_connman_element_is(element, e_connman_iface_profile);
+}
+
+Eina_Bool
+e_connman_element_is_service(const E_Connman_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return _e_connman_element_is(element, e_connman_iface_service);
+}
+
+Eina_Bool
+e_connman_element_is_technology(const E_Connman_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return _e_connman_element_is(element, e_connman_iface_technology);
+}
+
diff --git a/src/lib/connman0_7x/e_connman_manager.c b/src/lib/connman0_7x/e_connman_manager.c
new file mode 100644 (file)
index 0000000..f6cc5ed
--- /dev/null
@@ -0,0 +1,590 @@
+#include "e_connman_private.h"
+
+/**
+ * Get the element manager.
+ *
+ * @return element pointer if found, NULL otherwise.
+ */
+E_Connman_Element *
+e_connman_manager_get(void)
+{
+   return e_connman_element_get(manager_path);
+}
+
+/**
+ * Register new agent for handling user requests.
+ *
+ * Call method RegisterAgent(object) on server in order to
+ * register new agent for handling user requests.
+ *
+ * @param object_path object to be registered.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_agent_register(const char *object_path, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "RegisterAgent";
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(object_path, EINA_FALSE);
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_call_with_path
+             (element, name, object_path, NULL,
+             &element->_pending.agent_register, cb, data);
+}
+
+/**
+ * Unregister an existing agent.
+ *
+ * Call method UnregisterAgent(object) on server in order to
+ * unregister an existing agent.
+ *
+ * @param object_path agent to be unregistered.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_agent_unregister(const char *object_path, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "UnregisterAgent";
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(object_path, EINA_FALSE);
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_call_with_path
+             (element, name, object_path, NULL,
+             &element->_pending.agent_unregister, cb, data);
+}
+
+/**
+ * Get property "State" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The global connection state of a system. Possible
+ * values are "online" if at least one connection exists
+ * and "offline" if no service is connected.
+ *
+ * In certain situations the state might change to
+ * the value "connected". This can only be seen if
+ * previously no connection was present.
+ *
+ * @param state where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_state_get(const char **state)
+{
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(state, EINA_FALSE);
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_property_get_stringshared
+             (element, e_connman_prop_state, NULL, state);
+}
+
+/**
+ * Get property "OfflineMode" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The offline mode indicates the global setting for switching all radios on or
+ * off. Changing offline mode to true results in powering down all devices that
+ * use radio technology. When leaving offline mode the individual policy of each
+ * technology decides to switch the radio back on or not.
+ *
+ * During offline mode, it is still possible to switch certain technologies
+ * manually back on. For example the limited usage of WiFi or Bluetooth
+ * technologies might be allowed in some situations.
+ *
+ * @param offline where to store the property value, must be a pointer
+ *        to Eina_Bool (Eina_Bool *).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_connman_manager_offline_mode_set()
+ */
+Eina_Bool
+e_connman_manager_offline_mode_get(Eina_Bool *offline)
+{
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(offline, EINA_FALSE);
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_property_get_stringshared
+             (element, e_connman_prop_offline_mode, NULL, offline);
+}
+
+/**
+ * Call method SetProperty("OfflineMode", offline) at the given element on server.
+ *
+ * This is a server call, not local, so it may fail and in that case
+ * no property is updated locally. If the value was set the event
+ * E_CONNMAN_EVENT_ELEMENT_UPDATED will be added to main loop.
+ *
+ * The offline mode indicates the global setting for switching all radios on or
+ * off. Changing offline mode to true results in powering down all devices that
+ * use radio technology. When leaving offline mode the individual policy of each
+ * technology decides to switch the radio back on or not.
+ *
+ * During offline mode, it is still possible to switch certain technologies
+ * manually back on. For example the limited usage of WiFi or Bluetooth
+ * technologies might be allowed in some situations.
+ *
+ * @param offline value to set.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_connman_manager_offline_mode_get()
+ */
+Eina_Bool
+e_connman_manager_offline_mode_set(Eina_Bool offline, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   E_Connman_Element *element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_property_set_full
+             (element, e_connman_prop_offline_mode, DBUS_TYPE_BOOLEAN,
+             &offline, cb, data);
+}
+
+/**
+ * Get array of profile elements.
+ *
+ * @param count return the number of elements in array.
+ * @param p_elements array with all elements, these are not referenced
+ *        and in no particular order, just set if return is @c EINA_TRUE.  The
+ *        array itself is allocated using malloc() and should be freed
+ *        after usage is done.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_profiles_get(unsigned int *count, E_Connman_Element ***p_elements)
+{
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_objects_array_get_stringshared
+             (element, e_connman_prop_profiles, count, p_elements);
+}
+
+/**
+ * Get array of services elements.
+ *
+ * List of service object paths. The list is sorted
+ * internally to have the service with the default
+ * route always first and then the favorite services
+ * followed by scan results.
+ *
+ * This list represents the available services for the
+ * current selected profile. If the profile gets changed
+ * then this list will be updated.
+ *
+ * The same list is available via the profile object
+ * itself. It is just provided here for convenience of
+ * applications only dealing with the current active
+ * profile.
+ *
+ * @param count return the number of elements in array.
+ * @param p_elements array with all elements, these are not referenced
+ *        and in no particular order, just set if return is @c EINA_TRUE.  The
+ *        array itself is allocated using malloc() and should be freed
+ *        after usage is done.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_services_get(unsigned int *count, E_Connman_Element ***p_elements)
+{
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_objects_array_get_stringshared
+             (element, e_connman_prop_services, count, p_elements);
+}
+
+/**
+ * Get array of technology elements.
+ *
+ * @param count return the number of elements in array.
+ * @param p_elements array with all elements, these are not referenced
+ *        and in no particular order, just set if return is @c EINA_TRUE.  The
+ *        array itself is allocated using malloc() and should be freed
+ *        after usage is done.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_technologies_get(unsigned int *count, E_Connman_Element ***p_elements)
+{
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_objects_array_get_stringshared
+             (element, e_connman_prop_technologies, count, p_elements);
+}
+
+/**
+ * Request to trigger a scan for given technology.
+ *
+ * Call method RequestScan(type) on server in order to find new services for
+ * such technology type.
+ *
+ * The empty string for type means all technolgies.
+ *
+ * @param type technology type to scan. Empty or NULL for all technologies.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_request_scan(const char *type, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "RequestScan";
+   E_Connman_Element *element;
+
+   if (!type)
+      type = "";
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_call_with_string
+             (element, name, type, NULL,
+             &element->_pending.request_scan, cb, data);
+}
+
+/**
+ * Enable specified type of technology.
+ *
+ * Call method EnableTechnology(type) on server.
+ *
+ * @param type technology type to enable.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_technology_enable(const char *type, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "EnableTechnology";
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_call_with_string
+             (element, name, type, NULL,
+             &element->_pending.technology_enable, cb, data);
+}
+
+/**
+ * Disable specified type of technology.
+ *
+ * Call method DisableTechnology(type) on server.
+ *
+ * @param type technology type to disable.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_technology_disable(const char *type, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "DisableTechnology";
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_call_with_string
+             (element, name, type, NULL,
+             &element->_pending.technology_disable, cb, data);
+}
+
+/**
+ * Get property "DefaultTechnology" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The current connected technology which holds the default route.
+ *
+ * @param type where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_technology_default_get(const char **type)
+{
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_property_get_stringshared
+             (element, e_connman_prop_technology_default, NULL, type);
+}
+
+/**
+ * Remove specified profile.
+ *
+ * Call method RemoveProfile(profile) on server.
+ *
+ * It is not possible to remove the current active profile. To remove
+ * the active profile a different one must be selected via
+ * ActiveProfile property first.
+ *
+ * At minimum one profile must be available all the time.
+ *
+ * @param profile element to remove, must be of type profile.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_profile_remove(const E_Connman_Element *profile, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   E_Connman_Element *element;
+   const char name[] = "RemoveProfile";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(profile, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(profile->path, EINA_FALSE);
+
+   if (!e_connman_element_is_profile(profile))
+      return EINA_FALSE;
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_call_with_path
+             (element, name, profile->path, NULL,
+             &element->_pending.profile_remove, cb, data);
+}
+
+/**
+ * Get property "ActiveProfile" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element where to store the element, just changed if return is @c EINA_TRUE
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * @see e_connman_manager_profile_active_set()
+ */
+Eina_Bool
+e_connman_manager_profile_active_get(E_Connman_Element **profile)
+{
+   E_Connman_Element *element;
+   char *profile_path;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(profile, EINA_FALSE);
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   if (!e_connman_element_property_get_stringshared
+          (element, e_connman_prop_profile_active, NULL, &profile_path))
+      return EINA_FALSE;
+
+   *profile = e_connman_element_get(profile_path);
+   return EINA_TRUE;
+}
+
+/**
+ * Call method SetProperty("ActiveProfile", profile) at the given
+ * element on server.
+ *
+ * This is a server call, not local, so it may fail and in that case
+ * no property is updated locally. If the value was set the event
+ * E_CONNMAN_EVENT_ELEMENT_UPDATED will be added to main loop.
+ *
+ * @param profile object to set.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_connman_manager_profile_active_get()
+ */
+Eina_Bool
+e_connman_manager_profile_active_set(const E_Connman_Element *profile, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(profile, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(profile->path, EINA_FALSE);
+
+   if (!e_connman_element_is_profile(profile))
+      return EINA_FALSE;
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_property_set_full
+             (element, e_connman_prop_profile_active, DBUS_TYPE_OBJECT_PATH,
+             profile->path, cb, data);
+}
+
+/**
+ * Get array of strings representing the available technologies.
+ *
+ * @param count return the number of elements in array.
+ * @param p_strings array with pointers to internal strings. These
+ *        strings are not copied in any way, and they are granted to
+ *        be eina_stringshare instances, so one can use
+ *        eina_stringshare_ref() if he wants to save memory and cpu to
+ *        get an extra reference. The array itself is allocated using
+ *        malloc() and should be freed after usage is done. This
+ *        pointer is just set if return is @c EINA_TRUE.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_technologies_available_get(unsigned int *count, const char ***p_strings)
+{
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_strings, EINA_FALSE);
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_strings_array_get_stringshared
+             (element, e_connman_prop_technologies_available, count, p_strings);
+}
+
+/**
+ * Get array of strings representing the enabled technologies.
+ *
+ * @param count return the number of elements in array.
+ * @param p_strings array with pointers to internal strings. These
+ *        strings are not copied in any way, and they are granted to
+ *        be eina_stringshare instances, so one can use
+ *        eina_stringshare_ref() if he wants to save memory and cpu to
+ *        get an extra reference. The array itself is allocated using
+ *        malloc() and should be freed after usage is done. This
+ *        pointer is just set if return is @c EINA_TRUE.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_technologies_enabled_get(unsigned int *count, const char ***p_strings)
+{
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_strings, EINA_FALSE);
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_strings_array_get_stringshared
+             (element, e_connman_prop_technologies_enabled, count, p_strings);
+}
+
+/**
+ * Get array of strings representing the connected technologies.
+ *
+ * @param count return the number of elements in array.
+ * @param p_strings array with pointers to internal strings. These
+ *        strings are not copied in any way, and they are granted to
+ *        be eina_stringshare instances, so one can use
+ *        eina_stringshare_ref() if he wants to save memory and cpu to
+ *        get an extra reference. The array itself is allocated using
+ *        malloc() and should be freed after usage is done. This
+ *        pointer is just set if return is @c EINA_TRUE.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_manager_technologies_connected_get(unsigned int *count, const char ***p_strings)
+{
+   E_Connman_Element *element;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_strings, EINA_FALSE);
+
+   element = e_connman_manager_get();
+   if (!element)
+      return EINA_FALSE;
+
+   return e_connman_element_strings_array_get_stringshared
+             (element, e_connman_prop_technologies_connected, count, p_strings);
+}
+
diff --git a/src/lib/connman0_7x/e_connman_private.h b/src/lib/connman0_7x/e_connman_private.h
new file mode 100644 (file)
index 0000000..d6f98f9
--- /dev/null
@@ -0,0 +1,174 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *    alloca (size_t);
+#endif
+
+#include <stdio.h>
+
+#include <Eina.h>
+#include <eina_safety_checks.h>
+
+#define E_CONNMAN_I_KNOW_THIS_API_IS_SUBJECT_TO_CHANGE 1
+#include "E_Connman.h"
+
+typedef struct _E_Connman_Array E_Connman_Array;
+struct _E_Connman_Array
+{
+   int         type;
+   Eina_Array *array;
+};
+
+static const char manager_path[] = "/";
+
+extern const char *e_connman_iface_manager;
+extern const char *e_connman_iface_profile;
+extern const char *e_connman_iface_service;
+extern const char *e_connman_iface_connection;
+extern const char *e_connman_iface_technology;
+
+extern const char *e_connman_prop_ipv4;
+extern const char *e_connman_prop_ipv4_configuration;
+extern const char *e_connman_prop_ethernet;
+extern const char *e_connman_prop_interface;
+extern const char *e_connman_prop_speed;
+extern const char *e_connman_prop_duplex;
+extern const char *e_connman_prop_method;
+extern const char *e_connman_prop_address;
+extern const char *e_connman_prop_gateway;
+extern const char *e_connman_prop_netmask;
+extern const char *e_connman_prop_mtu;
+extern const char *e_connman_prop_name;
+extern const char *e_connman_prop_offline_mode;
+extern const char *e_connman_prop_profiles;
+extern const char *e_connman_prop_profile_active;
+extern const char *e_connman_prop_services;
+extern const char *e_connman_prop_technologies;
+extern const char *e_connman_prop_state;
+extern const char *e_connman_prop_strength;
+extern const char *e_connman_prop_type;
+extern const char *e_connman_prop_error;
+extern const char *e_connman_prop_security;
+extern const char *e_connman_prop_passphrase;
+extern const char *e_connman_prop_passphrase_required;
+extern const char *e_connman_prop_favorite;
+extern const char *e_connman_prop_immutable;
+extern const char *e_connman_prop_auto_connect;
+extern const char *e_connman_prop_roaming;
+extern const char *e_connman_prop_technology_default;
+extern const char *e_connman_prop_technologies_available;
+extern const char *e_connman_prop_technologies_enabled;
+extern const char *e_connman_prop_technologies_connected;
+extern const char *e_connman_prop_login_required;
+extern const char *e_connman_prop_nameservers;
+extern const char *e_connman_prop_nameservers_configuration;
+extern const char *e_connman_prop_domains;
+extern const char *e_connman_prop_domains_configuration;
+extern const char *e_connman_prop_proxy;
+extern const char *e_connman_prop_proxy_configuration;
+extern const char *e_connman_prop_url;
+extern const char *e_connman_prop_servers;
+extern const char *e_connman_prop_excludes;
+
+extern int _e_dbus_connman_log_dom;
+
+#ifndef EINA_LOG_DEFAULT_COLOR
+#define EINA_LOG_DEFAULT_COLOR EINA_COLOR_CYAN
+#endif
+
+#undef DBG
+#undef INF
+#undef WRN
+#undef ERR
+
+#define DBG(...) EINA_LOG_DOM_DBG(_e_dbus_connman_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_e_dbus_connman_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_e_dbus_connman_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_e_dbus_connman_log_dom, __VA_ARGS__)
+
+static inline Eina_Bool
+_dbus_callback_check_and_init(DBusMessage *msg, DBusMessageIter *itr, DBusError *err)
+{
+   if (!msg)
+     {
+        if (err && (err->name[0] == 'C'))
+          return EINA_FALSE;
+        if (err)
+          {
+             /* dont keep reporting the same err again and again */
+             static char perr[256] = {0};
+             
+             if (!(!strncmp(perr, err->name, sizeof(perr) - 1)))
+               {
+                  ERR("an error was reported by server: "
+                      "name=\"%s\", message=\"%s\"",
+                      err->name, err->message);
+                  strncpy(perr, err->name, sizeof(perr) - 1);
+                  perr[sizeof(perr) - 1] = 0;
+               }
+          }
+        else
+           ERR("callback without message arguments!");
+
+        return EINA_FALSE;
+     }
+
+   if (!dbus_message_iter_init(msg, itr))
+     {
+        ERR("could not init iterator.");
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static inline Eina_Bool
+__dbus_iter_type_check(int type, int expected, const char *expected_name)
+{
+   if (type == expected)
+      return EINA_TRUE;
+
+   ERR("expected type %s (%c) but got %c instead!",
+       expected_name, expected, type);
+
+   return EINA_FALSE;
+}
+
+#define _dbus_iter_type_check(t, e) __dbus_iter_type_check(t, e, # e)
+
+extern E_DBus_Connection *e_connman_conn;
+
+const char *           e_connman_system_bus_name_get(void);
+
+void                   e_connman_manager_clear_elements(void);
+
+void                   e_connman_elements_init(void);
+void                   e_connman_elements_shutdown(void);
+
+E_Connman_Element *    e_connman_element_register(const char *path, const char *interface);
+void                   e_connman_element_unregister(E_Connman_Element *element);
+
+Eina_Bool              e_connman_element_objects_array_get_stringshared(const E_Connman_Element *element, const char *property, unsigned int *count, E_Connman_Element ***elements);
+Eina_Bool              e_connman_element_strings_array_get_stringshared(const E_Connman_Element *element, const char *property, unsigned int *count, const char ***strings);
+unsigned char *        e_connman_element_bytes_array_get_stringshared(const E_Connman_Element *element, const char *property, unsigned int *count);
+
+Eina_Bool              e_connman_element_message_send(E_Connman_Element *element, const char *method_name, E_DBus_Method_Return_Cb cb, DBusMessage *msg, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data);
+
+Eina_Bool              e_connman_element_call_full(E_Connman_Element *element, const char *method_name, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data);
+Eina_Bool              e_connman_element_call_with_path(E_Connman_Element *element, const char *method_name, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data);
+Eina_Bool              e_connman_element_call_with_string(E_Connman_Element *element, const char *method_name, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data);
diff --git a/src/lib/connman0_7x/e_connman_profile.c b/src/lib/connman0_7x/e_connman_profile.c
new file mode 100644 (file)
index 0000000..70c0dcf
--- /dev/null
@@ -0,0 +1,143 @@
+#include "e_connman_private.h"
+
+E_Connman_Element *
+e_connman_profile_get(const char *path)
+{
+   E_Connman_Element *profile;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+
+   profile = e_connman_element_get(path);
+   if (!profile)
+      return NULL;
+
+   if (!e_connman_element_is_profile(profile))
+     {
+        WRN("path '%s' is not a profile!", path);
+        return NULL;
+     }
+
+   return profile;
+}
+
+/**
+ * Get property "Name" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The profile name, if set with e_connman_profile_name_set()
+ *
+ * @param profile path to get property.
+ * @param name where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_connman_profile_name_set()
+ */
+Eina_Bool
+e_connman_profile_name_get(const E_Connman_Element *profile, const char **name)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(profile, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (profile, e_connman_prop_name, NULL, name);
+}
+
+/**
+ * Call method SetProperty("Name", name) at the given element on server.
+ *
+ * This is a server call, not local, so it may fail and in that case
+ * no property is updated locally. If the value was set the event
+ * E_CONNMAN_EVENT_ELEMENT_UPDATED will be added to main loop.
+ *
+ * @param name value to set.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_connman_profile_name_get()
+ */
+Eina_Bool
+e_connman_profile_name_set(E_Connman_Element *profile, const char *name, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(profile, EINA_FALSE);
+   return e_connman_element_property_set_full
+             (profile, e_connman_prop_name, DBUS_TYPE_STRING, name, cb, data);
+}
+
+/**
+ * Get property "OfflineMode" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The offline mode indicates the global setting for switching all radios on or
+ * off. Changing offline mode to true results in powering down all devices that
+ * use radio technology.
+ *
+ * @param offline where to store the property value, must be a pointer
+ *        to Eina_Bool (Eina_Bool *).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_connman_profile_offline_mode_set()
+ */
+Eina_Bool
+e_connman_profile_offline_mode_get(const E_Connman_Element *profile, Eina_Bool *offline)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(profile, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(offline, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (profile, e_connman_prop_offline_mode, NULL, offline);
+}
+
+/**
+ * Call method SetProperty("OfflineMode", offline) at the given element on server.
+ *
+ * This is a server call, not local, so it may fail and in that case
+ * no property is updated locally. If the value was set the event
+ * E_CONNMAN_EVENT_ELEMENT_UPDATED will be added to main loop.
+ *
+ * The offline mode indicates the global setting for switching all radios on or
+ * off. Changing offline mode to true results in powering down all devices that
+ * use radio technology.
+ *
+ * @param offline value to set.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_connman_profile_offline_mode_get()
+ */
+Eina_Bool
+e_connman_profile_offline_mode_set(E_Connman_Element *profile, Eina_Bool offline, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(profile, EINA_FALSE);
+   return e_connman_element_property_set_full
+             (profile, e_connman_prop_offline_mode, DBUS_TYPE_BOOLEAN,
+             &offline, cb, data);
+}
+
+/**
+ * Get array of service elements.
+ *
+ * @param count return the number of elements in array.
+ * @param p_elements array with all elements, these are not referenced
+ *        and in no particular order, just set if return is @c EINA_TRUE.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_profile_services_get(const E_Connman_Element *profile, unsigned int *count, E_Connman_Element ***p_elements)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(profile, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
+   return e_connman_element_objects_array_get_stringshared
+             (profile, e_connman_prop_services, count, p_elements);
+}
+
diff --git a/src/lib/connman0_7x/e_connman_service.c b/src/lib/connman0_7x/e_connman_service.c
new file mode 100644 (file)
index 0000000..0c6c320
--- /dev/null
@@ -0,0 +1,1646 @@
+#include "e_connman_private.h"
+
+E_Connman_Element *
+e_connman_service_get(const char *path)
+{
+   E_Connman_Element *service;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+
+   service = e_connman_element_get(path);
+   if (!service)
+      return NULL;
+
+   if (!e_connman_element_is_service(service))
+     {
+        WRN("path '%s' is not a service!", path);
+        return NULL;
+     }
+
+   return service;
+}
+
+/**
+ * Connect this service.
+ *
+ * Connect this service. It will attempt to connect
+ * WiFi, WiMAX or Bluetooth services.
+ *
+ * For Ethernet devices this method can only be used
+ * if it has previously been disconnected. Otherwise
+ * the plugging of a cable will trigger connecting
+ * automatically. If no cable is plugged in this method
+ * will fail.
+ *
+ * @param service path to call method on server.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_connect(E_Connman_Element *service, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "Connect";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   return e_connman_element_call_full
+             (service, name, NULL, &service->_pending.service_connect, cb, data);
+}
+
+/**
+ * Disconnect this service.
+ *
+ * Disconnect this service. If the service is not
+ * connected an error message will be generated.
+ *
+ * On Ethernet devices this will disconnect the IP
+ * details from the service. It will not magically
+ * unplug the cable. When no cable is plugged in this
+ * method will fail.
+ *
+ * This method can also be used to abort a previous
+ * connectiong attempt via the Connect method.
+ *
+ * @param service path to call method on server.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_disconnect(E_Connman_Element *service, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "Disconnect";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   return e_connman_element_call_full
+             (service, name, NULL, &service->_pending.service_disconnect, cb, data);
+}
+
+/**
+ * Remove this service.
+ *
+ * A successfully connected service with Favorite=true
+ * can be removed this way. If it is connected, it will
+ * be automatically disconnected first.
+ *
+ * If the service requires a passphrase it will be
+ * cleared and forgotten when removing.
+ *
+ * This is similar to setting the Favorite property
+ * to false, but that is currently not supported.
+ *
+ * In the case a connection attempt failed and the
+ * service is in the State=failure, this method can
+ * also be used to reset the service.
+ *
+ * Calling this method on Ethernet devices will cause
+ * an error message. It is not possible to remove these
+ * kind of devices.
+ *
+ * @param service path to call method on server.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_remove(E_Connman_Element *service, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "Remove";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   return e_connman_element_call_full
+             (service, name, NULL, &service->_pending.service_remove, cb, data);
+}
+
+/**
+ * Clears the value of the specified property.
+ *
+ *
+ * @param service path to call method on server.
+ * @param property to be cleared.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_clear_property(E_Connman_Element *service, const char *property, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "ClearProperty";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(property, EINA_FALSE);
+   return e_connman_element_call_with_string
+             (service, name, property, NULL, &service->_pending.service_clear_property,
+             cb, data);
+}
+
+/**
+ * Move service before in favorites list.
+ *
+ * Call method MoveBefore(object service) at the given service on server.
+ *
+ * If a service has been used before, this allows a
+ * reorder of the favorite services.
+ *
+ * The target service object must be part of this
+ * profile. Moving between profiles is not supported.
+ *
+ * @param service path to call method on server.
+ * @param object_path object service.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_move_before(E_Connman_Element *service, const char *object_path, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "MoveBefore";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(object_path, EINA_FALSE);
+   return e_connman_element_call_with_path
+             (service, name, object_path, NULL,
+             &service->_pending.service_move_before, cb, data);
+}
+
+/**
+ * Move service after in favorites list.
+ *
+ * Call method MoveAfter(object service) at the given service on server.
+ *
+ * If a service has been used before, this allows a
+ * reorder of the favorite services.
+ *
+ * The target service object must be part of this
+ * profile. Moving between profiles is not supported.
+ *
+ * @param service path to call method on server.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_move_after(E_Connman_Element *service, const char *object_path, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "MoveAfter";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(object_path, EINA_FALSE);
+   return e_connman_element_call_with_path
+             (service, name, object_path, NULL,
+             &service->_pending.service_move_after, cb, data);
+}
+
+/**
+ * Get property "State" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The service state information.
+ *
+ * Valid states are "idle", "failure", "association",
+ * "configuration", "ready", "login" and "online".
+ *
+ * @param service path to get property.
+ * @param state where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_state_get(const E_Connman_Element *service, const char **state)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(state, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (service, e_connman_prop_state, NULL, state);
+}
+
+/**
+ * Get property "Error" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The service error status details.
+ *
+ * When error occur during connection or disconnection
+ * the detailed information are represented in this
+ * property to help the user interface to present the
+ * user with alternate options.
+ *
+ * This property is only valid when the service is in
+ * the "failure" state. Otherwise it might be empty or
+ * not present at all.
+ *
+ * Current defined error code is "dhcp-failed".
+ *
+ * @param service path to get property.
+ * @param error where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_error_get(const E_Connman_Element *service, const char **error)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(error, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (service, e_connman_prop_error, NULL, error);
+}
+
+/**
+ * Get property "Name" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The service name (for example "Wireless" etc.)
+ *
+ * This name can be used for directly displaying it in
+ * the application. It has pure informational purpose.
+ *
+ * For Ethernet devices and hidden WiFi networks it is
+ * not guaranteed that this property is present.
+ *
+ * @param service path to get property.
+ * @param name where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_name_get(const E_Connman_Element *service, const char **name)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (service, e_connman_prop_name, NULL, name);
+}
+
+/**
+ * Get property "Type" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The service type (for example "ethernet", "wifi" etc.)
+ *
+ * This information should only be used to determine
+ * advanced properties or showing the correct icon
+ * to the user.
+ *
+ * @param service path to get property.
+ * @param type where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_type_get(const E_Connman_Element *service, const char **type)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (service, e_connman_prop_type, NULL, type);
+}
+
+/**
+ * Get property "Security" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * If the service type is WiFi, then this property is
+ * present and contains the list of security method or key
+ * management setting.
+ *
+ * Possible values are "none", "wep", "wpa", "rsn", "psk", "ieee8021x" and "wps"
+ *
+ * This property might be only present for WiFi
+ * services.
+ *
+ * @param service path to get property.
+ * @param count where to return the number of elements in @a security
+ * @param security where to store the property value, must be a pointer
+ *        to array of strings, it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_security_get(const E_Connman_Element *service, unsigned int *count, const char ***security)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(security, EINA_FALSE);
+
+   return e_connman_element_strings_array_get_stringshared
+     (service, e_connman_prop_security, count, security);
+}
+
+/**
+ * Get property "Passphrase" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * If the service type is WiFi, then this property
+ * can be used to store a passphrase.
+ *
+ * No PropertyChanged signals will be send for this
+ * property. The PassphraseRequired property should
+ * be monitored instead.
+ *
+ * This property might also not always be included
+ * since it is protected by a different security policy.
+ *
+ * @param service path to get property.
+ * @param passphrase where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_connman_service_passphrase_set()
+ */
+Eina_Bool
+e_connman_service_passphrase_get(const E_Connman_Element *service, const char **passphrase)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(passphrase, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (service, e_connman_prop_passphrase, NULL, passphrase);
+}
+
+/**
+ * Set property "Passphrase" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * If the service type is WiFi, then this property
+ * can be used to store a passphrase.
+ *
+ * No PropertyChanged signals will be send for this
+ * property. The PassphraseRequired property should
+ * be monitored instead.
+ *
+ * This property might also not always be included
+ * since it is protected by a different security policy.
+ *
+ * @param service path to get property.
+ * @param passphrase value to set.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_connman_service_passphrase_get()
+ */
+Eina_Bool
+e_connman_service_passphrase_set(E_Connman_Element *service, const char *passphrase, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   return e_connman_element_property_set_full
+             (service, e_connman_prop_passphrase, DBUS_TYPE_STRING,
+             passphrase, cb, data);
+}
+
+/**
+ * Get property "PassphraseRequired" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * If the service type is WiFi, then this property
+ * indicates if a passphrase is required.
+ *
+ * If a passphrase has been set already or if no
+ * passphrase is needed, then this property will
+ * be set to false.
+ *
+ * @param service path to get property.
+ * @param passphrase_required where to store the property value, must be a
+ *        pointer to Eina_Bool (Eina_Bool *).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_passphrase_required_get(const E_Connman_Element *service, Eina_Bool *passphrase_required)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(passphrase_required, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (service, e_connman_prop_passphrase_required, NULL, passphrase_required);
+}
+
+/**
+ * Get property "LoginRequired" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * Indicates that a manual configuration must be done to login the
+ * user, likely access an website using a browser.
+ *
+ * If a login has been set already or if no
+ * login is needed, then this property will
+ * be set to false.
+ *
+ * @param service path to get property.
+ * @param login_required where to store the property value, must be a
+ *        pointer to Eina_Bool (Eina_Bool *).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * @since 1.1.0
+ */
+Eina_Bool
+e_connman_service_login_required_get(const E_Connman_Element *service, Eina_Bool *login_required)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(login_required, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (service, e_connman_prop_login_required, NULL, login_required);
+}
+
+/**
+ * Get property "Strength" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * Indicates the signal strength of the service. This
+ * is a normalized value between 0 and 100.
+ *
+ * This property will not be present for Ethernet
+ * devices.
+ *
+ * @param service path to get property.
+ * @param strength where to store the property value, must be a pointer
+ *        to byte (unsigned char*).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_strength_get(const E_Connman_Element *service, unsigned char *strength)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(strength, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (service, e_connman_prop_strength, NULL, strength);
+}
+
+/**
+ * Get property "Favorite" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * Will be true if a cable is plugged in or the user
+ * selected and successfully connected to this service.
+ *
+ * This value is automatically changed and to revert
+ * it back to false the Remove() method needs to be
+ * used.
+ *
+ * @param service path to get property.
+ * @param favorite where to store the property value, must be a
+ *        pointer to Eina_Bool (Eina_Bool *).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_favorite_get(const E_Connman_Element *service, Eina_Bool *favorite)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(favorite, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (service, e_connman_prop_favorite, NULL, favorite);
+}
+
+/**
+ * Get property "Immutable" value.
+ *
+ * This value will be set to true if the service is configured
+ * externally via a configuration file.
+ *
+ * The only valid operation are e_connman_service_connect() and
+ * e_connman_service_disconnect(). The e_connman_service_remove()
+ * method will result in an error.
+
+ * @param service path to get property.
+ * @param immutable where to store the property value, must be a
+ *        pointer to Eina_Bool (Eina_Bool *).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_immutable_get(const E_Connman_Element *service, Eina_Bool *immutable)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(immutable, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (service, e_connman_prop_immutable, NULL, immutable);
+}
+
+/**
+ * Get property "AutoConnect" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * If set to true, this service will auto-connect
+ * when not other connection is available.
+ *
+ * For favorite services it is possible to change
+ * this value to prevent or permit automatic
+ * connection attempts.
+ *
+ * @param service path to get property.
+ * @param auto_connect where to store the property value, must be a
+ *        pointer to Eina_Bool (Eina_Bool *).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_connman_service_auto_connect_set()
+ */
+Eina_Bool
+e_connman_service_auto_connect_get(const E_Connman_Element *service, Eina_Bool *auto_connect)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(auto_connect, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (service, e_connman_prop_auto_connect, NULL, auto_connect);
+}
+
+/**
+ * Set property "AutoConnect" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * If set to true, this service will auto-connect
+ * when not other connection is available.
+ *
+ * For favorite services it is possible to change
+ * this value to prevent or permit automatic
+ * connection attempts.
+ *
+ * @param service path to get property.
+ * @param service_favorite where to store the property value, must be a
+ *        pointer to Eina_Bool (Eina_Bool *).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_connman_service_auto_connect_get()
+ */
+Eina_Bool
+e_connman_service_auto_connect_set(E_Connman_Element *service, Eina_Bool auto_connect, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   return e_connman_element_property_set_full
+             (service, e_connman_prop_auto_connect, DBUS_TYPE_BOOLEAN, &auto_connect, cb, data);
+}
+
+/**
+ * Get property "Roaming" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * This property indicates if this service is roaming.
+ *
+ * In the case of Cellular services this normally
+ * indicates connections to a foreign provider when
+ * traveling abroad.
+ *
+ * @param service path to get property.
+ * @param roaming where to store the property value, must be a
+ *        pointer to Eina_Bool (Eina_Bool *).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_roaming_get(const E_Connman_Element *service, Eina_Bool *roaming)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(roaming, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (service, e_connman_prop_roaming, NULL, roaming);
+}
+
+/**
+ * Get property "Nameservers" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ * The list of currently active nameservers for this service. If the server is
+ * not in READY or ONLINE state than this list will be empty.
+ *
+ * Global nameservers are automatically added to this list.
+ *
+ * The array represents a sorted list of the current nameservers. The first one
+ * has the highest priority and is used by default.
+ *
+ * When using DHCP this array represents the nameservers provided by the
+ * network. In case of manual settings, the ones from Nameservers.Configuration
+ * are used.
+ *
+ * @param service path to get property.
+ * @param count return the number of elements in array.
+ * @param nameservers array with pointers to internal strings. These
+ *        strings are not copied in any way, and they are granted to
+ *        be eina_stringshare instances, so one can use
+ *        eina_stringshare_ref() if he wants to save memory and cpu to
+ *        get an extra reference. The array itself is also NOT
+ *        allocated or copied, do not modify it. This pointer is just
+ *        set if return is @c EINA_TRUE.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_nameservers_get(const E_Connman_Element *service, unsigned int *count, const char ***nameservers)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(nameservers, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   return e_connman_element_strings_array_get_stringshared
+             (service, e_connman_prop_nameservers, count, nameservers);
+}
+
+/**
+ * Get property "Nameservers.Configuration" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ * The list of currently active nameservers for this service. If the server is
+ * not in READY or ONLINE state than this list will be empty.
+ *
+ * Unlike Nameservers, this is the user-set value, rather than the
+ * actual value.
+ *
+ * @param service path to get property.
+ * @param count return the number of elements in array.
+ * @param nameservers array with pointers to internal strings. These
+ *        strings are not copied in any way, and they are granted to
+ *        be eina_stringshare instances, so one can use
+ *        eina_stringshare_ref() if he wants to save memory and cpu to
+ *        get an extra reference. The array itself is also NOT
+ *        allocated or copied, do not modify it. This pointer is just
+ *        set if return is @c EINA_TRUE.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_nameservers_configuration_get(const E_Connman_Element *service, unsigned int *count, const char ***nameservers)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(nameservers, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   return e_connman_element_strings_array_get_stringshared
+             (service, e_connman_prop_nameservers_configuration,
+              count, nameservers);
+}
+
+/**
+ * Set property "Nameservers.Configuration" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * Unlike Nameservers, this is the user-set value, rather than the actual value.
+ * It allows user to override the default setting.  When using manual
+ * configuration and no global nameservers are configured, then it is useful to
+ * configure this setting as well.
+ *
+ * This list is sorted by priority and the first entry represents the nameserver
+ * with the highest priority.
+ *
+ * Changes to the domain name servers can be done at any time. It will not cause
+ * a disconnect of the service. However there might be small window where name
+ * resolution might fail.
+ *
+ * @param service path to set property.
+ * @param nameservers sorted list of the current nameservers. The first one has
+ * the highest priority and is used by default.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_connman_service_nameservers_configuration_get()
+ */
+Eina_Bool
+e_connman_service_nameservers_configuration_set(E_Connman_Element *service, unsigned int count, const char **nameservers, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(nameservers, EINA_FALSE);
+   return e_connman_element_property_array_set_full
+             (service, e_connman_prop_nameservers_configuration,
+              DBUS_TYPE_STRING, count,
+              (const void * const *)nameservers, cb, data);
+}
+
+/**
+ * Get property "Domains" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ * The list of currently active domains for this service. If the server is
+ * not in READY or ONLINE state than this list will be empty.
+ *
+ * The list of currently used search domains.
+ *
+ * @param service path to get property.
+ * @param count return the number of elements in array.
+ * @param domains array with pointers to internal strings. These
+ *        strings are not copied in any way, and they are granted to
+ *        be eina_stringshare instances, so one can use
+ *        eina_stringshare_ref() if he wants to save memory and cpu to
+ *        get an extra reference. The array itself is also NOT
+ *        allocated or copied, do not modify it. This pointer is just
+ *        set if return is @c EINA_TRUE.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_domains_get(const E_Connman_Element *service, unsigned int *count, const char ***domains)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(domains, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   return e_connman_element_strings_array_get_stringshared
+             (service, e_connman_prop_domains, count, domains);
+}
+
+/**
+ * Get property "Domains.Configuration" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ * The list of currently active domains for this service. If the server is
+ * not in READY or ONLINE state than this list will be empty.
+ *
+ * Unlike Domains, this is the user-set value, rather than the
+ * actual value.
+ *
+ * @param service path to get property.
+ * @param count return the number of elements in array.
+ * @param domains array with pointers to internal strings. These
+ *        strings are not copied in any way, and they are granted to
+ *        be eina_stringshare instances, so one can use
+ *        eina_stringshare_ref() if he wants to save memory and cpu to
+ *        get an extra reference. The array itself is also NOT
+ *        allocated or copied, do not modify it. This pointer is just
+ *        set if return is @c EINA_TRUE.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_domains_configuration_get(const E_Connman_Element *service, unsigned int *count, const char ***domains)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(domains, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   return e_connman_element_strings_array_get_stringshared
+             (service, e_connman_prop_domains_configuration, count, domains);
+}
+
+/**
+ * Set property "Domains.Configuration" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * Unlike Domains, this is the user-set value, rather than the actual value.
+ * It allows user to override the default setting.  When using manual
+ * configuration and no global domains are configured, then it is useful to
+ * configure this setting as well.
+ *
+ * This list is sorted by priority and the first entry represents the nameserver
+ * with the highest priority.
+ *
+ * Changes to the domain name servers can be done at any time. It will not cause
+ * a disconnect of the service. However there might be small window where name
+ * resolution might fail.
+ *
+ * @param service path to set property.
+ * @param count number of elements in @a domain.
+ * @param domains sorted list of the current domains. The first one has
+ * the highest priority and is used by default.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @see e_connman_service_domains_configuration_get()
+ */
+Eina_Bool
+e_connman_service_domains_configuration_set(E_Connman_Element *service, unsigned int count, const char **domains, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(domains, EINA_FALSE);
+   return e_connman_element_property_array_set_full
+             (service, e_connman_prop_domains_configuration,
+              DBUS_TYPE_STRING, count,
+              (const void * const *)domains, cb, data);
+}
+
+/**
+ * Get property "IPv4.Method" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The IPv4 method in use. Possible values here are "dhcp" and
+ * "static".
+ *
+ * @param service path to get property.
+ * @param method where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ipv4_method_get(const E_Connman_Element *service, const char **method)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_ipv4, e_connman_prop_method, NULL, method);
+}
+
+/**
+ * Get property "IPv4.Address" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The current IPv4 address.
+ *
+ * @param service path to get property.
+ * @param address where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ipv4_address_get(const E_Connman_Element *service, const char **address)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_ipv4, e_connman_prop_address, NULL, address);
+}
+
+/**
+ * Get property "IPv4.Gateway" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The current IPv4 gateway.
+ *
+ * @param service path to get property.
+ * @param gateway where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ipv4_gateway_get(const E_Connman_Element *service, const char **gateway)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(gateway, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_ipv4, e_connman_prop_gateway, NULL, gateway);
+}
+
+/**
+ * Get property "IPv4.Netmask" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The current IPv4 netmask.
+ *
+ * @param service path to get property.
+ * @param netmask where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ipv4_netmask_get(const E_Connman_Element *service, const char **netmask)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(netmask, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_ipv4, e_connman_prop_netmask, NULL, netmask);
+}
+
+/**
+ * Get property "IPv4.Configuration.Method" value.
+ *
+ * Unlike IPv4.Method, this is the user-set value, rather than the
+ * actual value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The IPv4 configured method. Possible values here are "dhcp" and
+ * "static".
+ *
+ * @param service path to get property.
+ * @param method where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ipv4_configuration_method_get(const E_Connman_Element *service, const char **method)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_ipv4_configuration, e_connman_prop_method,
+             NULL, method);
+}
+
+/**
+ * Get property "IPv4.Configuration.Address" value.
+ *
+ * Unlike IPv4.Address, this is the user-set value, rather than the
+ * actual value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The current configured IPv4 address.
+ *
+ * @param service path to get property.
+ * @param address where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ipv4_configuration_address_get(const E_Connman_Element *service, const char **address)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_ipv4_configuration, e_connman_prop_address,
+             NULL, address);
+}
+
+/**
+ * Get property "IPv4.Configuration.Gateway" value.
+ *
+ * Unlike IPv4.Gateway, this is the user-set value, rather than the
+ * actual value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The current configured IPv4 gateway.
+ *
+ * @param service path to get property.
+ * @param gateway where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ipv4_configuration_gateway_get(const E_Connman_Element *service, const char **gateway)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(gateway, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_ipv4_configuration, e_connman_prop_gateway,
+             NULL, gateway);
+}
+
+/**
+ * Get property "IPv4.Configuration.Netmask" value.
+ *
+ * Unlike IPv4.Netmask, this is the user-set value, rather than the
+ * actual value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The current configured IPv4 netmask.
+ *
+ * @param service path to get property.
+ * @param netmask where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ipv4_configuration_netmask_get(const E_Connman_Element *service, const char **netmask)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(netmask, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_ipv4_configuration, e_connman_prop_netmask,
+             NULL, netmask);
+}
+
+/**
+ * Set IPv4 to connect automatically using DHCP.
+ *
+ * @param service path to set.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ipv4_configure_dhcp(E_Connman_Element *service, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char method[] = "dhcp";
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   return e_connman_element_property_dict_set_full
+             (service, e_connman_prop_ipv4_configuration, e_connman_prop_method,
+             DBUS_TYPE_STRING, method, cb, data);
+}
+
+/**
+ * Set IPv4 to connect using manually set parameters.
+ *
+ * @param service path to set.
+ * @param address IPv4 address.
+ * @param netmask IPv4 netmask, or @c NULL for "/32".
+ * @param gateway IPv4 gateway address.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ipv4_configure_manual(E_Connman_Element *service, const char *address, const char *netmask, const char *gateway, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "SetProperty";
+   const char *method = "manual"; /* not method[] as gcc screws it with dbus */
+   DBusMessage *msg;
+   DBusMessageIter itr, variant, dict, entry;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_connman_system_bus_name_get(), service->path, service->interface, name);
+
+   if (!msg)
+      return 0;
+
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic
+      (&itr, DBUS_TYPE_STRING, &e_connman_prop_ipv4_configuration);
+
+   if (dbus_message_iter_open_container
+       (&itr, DBUS_TYPE_VARIANT,
+           (DBUS_TYPE_ARRAY_AS_STRING
+               DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+               DBUS_TYPE_STRING_AS_STRING
+               DBUS_TYPE_STRING_AS_STRING
+               DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
+           &variant))
+     {
+        if (dbus_message_iter_open_container
+            (&variant, DBUS_TYPE_ARRAY,
+                (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                    DBUS_TYPE_STRING_AS_STRING
+                    DBUS_TYPE_STRING_AS_STRING
+                    DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
+                &dict))
+          {
+             if (dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry))
+               {
+                  dbus_message_iter_append_basic
+                    (&entry, DBUS_TYPE_STRING, &e_connman_prop_method);
+                  dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &method);
+                  dbus_message_iter_close_container(&dict, &entry);
+               }
+             if (dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry))
+               {
+                  dbus_message_iter_append_basic
+                    (&entry, DBUS_TYPE_STRING, &e_connman_prop_address);
+                  dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &address);
+                  dbus_message_iter_close_container(&dict, &entry);
+               }
+             if (netmask)
+               {
+                  if (dbus_message_iter_open_container
+                      (&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry))
+                    {
+                       dbus_message_iter_append_basic
+                         (&entry, DBUS_TYPE_STRING, &e_connman_prop_netmask);
+                       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &netmask);
+                       dbus_message_iter_close_container(&dict, &entry);
+                    }
+                  else
+                    {
+                       ERR("dbus_message_iter_open_container() failed");
+                    }
+               }
+             
+             if (gateway)
+               {
+                  if (dbus_message_iter_open_container
+                      (&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry))
+                    {
+                       dbus_message_iter_append_basic
+                         (&entry, DBUS_TYPE_STRING, &e_connman_prop_gateway);
+                       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &gateway);
+                       dbus_message_iter_close_container(&dict, &entry);
+                    }
+                  else
+                    {
+                       ERR("dbus_message_iter_open_container() failed");
+                    }
+               }
+             dbus_message_iter_close_container(&variant, &dict);
+          }
+        else
+          {
+             ERR("dbus_message_iter_open_container() failed");
+          }
+        dbus_message_iter_close_container(&itr, &variant);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+
+   return e_connman_element_message_send
+             (service, name, NULL, msg, &service->_pending.property_set, cb, data);
+}
+
+/**
+ * Get property "Proxy.Method" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * Possible values are "direct", "auto" and "manual".
+ *
+ * @param service path to get property.
+ * @param method where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_proxy_method_get(const E_Connman_Element *service, const char **method)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_proxy, e_connman_prop_method, NULL, method);
+}
+
+/**
+ * Get property "Proxy.URL" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * Automatic proxy configuration URL. Used by "auto" method.
+ *
+ * @param service path to get property.
+ * @param url where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_proxy_url_get(const E_Connman_Element *service, const char **url)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(url, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_proxy, e_connman_prop_url, NULL, url);
+}
+
+/**
+ * Get property "Proxy.Servers" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * List of proxy URIs. The URI without a protocol will be interpreted as the
+ * generic proxy URI. All others will target a specific protocol and only once.
+ * Example of generic proxy server entry would be like this:
+ * "server.example.com:911".
+ *
+ * Used when "manual" method is set.
+ *
+ * @param service path to get property.
+ * @param count return the number of elements in array.
+ * @param servers array with pointers to internal strings. These
+ *        strings are not copied in any way, and they are granted to
+ *        be eina_stringshare instances, so one can use
+ *        eina_stringshare_ref() if he wants to save memory and cpu to
+ *        get an extra reference. The array itself is also NOT
+ *        allocated or copied, do not modify it. This pointer is just
+ *        set if return is @c EINA_TRUE.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_proxy_servers_get(const E_Connman_Element *service, unsigned int *count, const char ***servers)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(servers, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   return e_connman_element_property_dict_strings_array_get_stringshared
+             (service, e_connman_prop_proxy, e_connman_prop_servers, count, servers);
+}
+
+/**
+ * Get property "Proxy.Excludes" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * List of hosts which can be accessed directly.
+ *
+ * Used when "manual" method is set.
+ *
+ * @param service path to get property.
+ * @param count return the number of elements in array.
+ * @param excludes array with pointers to internal strings. These
+ *        strings are not copied in any way, and they are granted to
+ *        be eina_stringshare instances, so one can use
+ *        eina_stringshare_ref() if he wants to save memory and cpu to
+ *        get an extra reference. The array itself is also NOT
+ *        allocated or copied, do not modify it. This pointer is just
+ *        set if return is @c EINA_TRUE.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_proxy_excludes_get(const E_Connman_Element *service, unsigned int *count, const char ***excludes)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(excludes, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   return e_connman_element_property_dict_strings_array_get_stringshared
+             (service, e_connman_prop_proxy, e_connman_prop_excludes, count, excludes);
+}
+
+/**
+ * Get property "Proxy.Configuration.Method" value.
+ *
+ * Unlike Proxy.Configuration.Method, this is the user-set value, rather than
+ * the actual value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * Possible values are "direct", "auto" and "manual".
+ *
+ * @param service path to get property.
+ * @param method where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_proxy_configuration_method_get(const E_Connman_Element *service, const char **method)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_proxy_configuration, e_connman_prop_method, NULL, method);
+}
+
+/**
+ * Get property "Proxy.Configuration.URL" value.
+ *
+ * Unlike Proxy.URL, this is the user-set value, rather than the
+ * actual value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * Automatic proxy configuration URL. Used by "auto" method.
+ *
+ * @param service path to get property.
+ * @param url where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_proxy_configuration_url_get(const E_Connman_Element *service, const char **url)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(url, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_proxy_configuration, e_connman_prop_url, NULL, url);
+}
+
+/**
+ * Get property "Proxy.Configuration.Servers" value.
+ *
+ * Unlike Proxy.Servers, this is the user-set value, rather than the
+ * actual value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * List of proxy URIs. The URI without a protocol will be interpreted as the
+ * generic proxy URI. All others will target a specific protocol and only once.
+ * Example of generic proxy server entry would be like this:
+ * "server.example.com:911".
+ *
+ * Used when "manual" method is set.
+ *
+ * @param service path to get property.
+ * @param count return the number of elements in array.
+ * @param servers array with pointers to internal strings. These
+ *        strings are not copied in any way, and they are granted to
+ *        be eina_stringshare instances, so one can use
+ *        eina_stringshare_ref() if he wants to save memory and cpu to
+ *        get an extra reference. The array itself is also NOT
+ *        allocated or copied, do not modify it. This pointer is just
+ *        set if return is @c EINA_TRUE.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_proxy_configuration_servers_get(const E_Connman_Element *service, unsigned int *count, const char ***servers)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(servers, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   return e_connman_element_property_dict_strings_array_get_stringshared
+             (service, e_connman_prop_proxy_configuration, e_connman_prop_servers, count, servers);
+}
+
+/**
+ * Get property "Proxy.Configuration.Excludes" value.
+ *
+ * Unlike Proxy.Excludes, this is the user-set value, rather than the
+ * actual value.
+
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * List of hosts which can be accessed directly.
+ *
+ * Used when "manual" method is set.
+ *
+ * @param service path to get property.
+ * @param count return the number of elements in array.
+ * @param excludes array with pointers to internal strings. These
+ *        strings are not copied in any way, and they are granted to
+ *        be eina_stringshare instances, so one can use
+ *        eina_stringshare_ref() if he wants to save memory and cpu to
+ *        get an extra reference. The array itself is also NOT
+ *        allocated or copied, do not modify it. This pointer is just
+ *        set if return is @c EINA_TRUE.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_proxy_configuration_excludes_get(const E_Connman_Element *service, unsigned int *count, const char ***excludes)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(excludes, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   return e_connman_element_property_dict_strings_array_get_stringshared
+             (service, e_connman_prop_proxy_configuration, e_connman_prop_excludes, count, excludes);
+}
+
+/**
+ * Get property "Ethernet.Interface" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * Interface name (for example eth0).
+ *
+ * @param service path to get property.
+ * @param iface where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ethernet_interface_get(const E_Connman_Element *service, const char **iface)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_ethernet, e_connman_prop_interface, NULL, iface);
+}
+
+/**
+ * Get property "Ethernet.Method" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The Ethernet configuration method. Possible values here "auto" and "manual".
+ *
+ * @param service path to get property.
+ * @param method where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ethernet_method_get(const E_Connman_Element *service, const char **method)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_ethernet, e_connman_prop_method, NULL, method);
+}
+
+/**
+ * Get property "Ethernet.Speed" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * Selected speed of the line. This information might not always be available.
+ *
+ * @param service path to get property.
+ * @param speed where to store the property value.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ethernet_speed_get(const E_Connman_Element *service, unsigned short *speed)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(speed, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_ethernet, e_connman_prop_speed, NULL, speed);
+}
+
+/**
+ * Get property "Ethernet.Address" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The current configured Ethernet address (mac-address).
+ *
+ * @param service path to get property.
+ * @param address where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ethernet_address_get(const E_Connman_Element *service, const char **address)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_ethernet, e_connman_prop_address, NULL, address);
+}
+
+/**
+ * Get property "Ethernet.Duplex" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * Selected duplex settings of the line. Possible values are "half" and "full".
+ * This information might not always be available.
+ *
+ * @param service path to get property.
+ * @param duplex where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ethernet_duplex_get(const E_Connman_Element *service, const char **duplex)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(duplex, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_ethernet, e_connman_prop_duplex, NULL, duplex);
+}
+
+/**
+ * Get property "Ethernet.MTU" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The current configured Ethernet MTU.
+ *
+ * @param service path to get property.
+ * @param gateway where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_service_ethernet_mtu_get(const E_Connman_Element *service, unsigned short *mtu)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(service, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(mtu, EINA_FALSE);
+   return e_connman_element_property_dict_get_stringshared
+             (service, e_connman_prop_ethernet, e_connman_prop_mtu, NULL, mtu);
+}
diff --git a/src/lib/connman0_7x/e_connman_technology.c b/src/lib/connman0_7x/e_connman_technology.c
new file mode 100644 (file)
index 0000000..62d4e78
--- /dev/null
@@ -0,0 +1,106 @@
+#include "e_connman_private.h"
+
+E_Connman_Element *
+e_connman_technology_get(const char *path)
+{
+   E_Connman_Element *technology;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+
+   technology = e_connman_element_get(path);
+   if (!technology)
+      return NULL;
+
+   if (!e_connman_element_is_technology(technology))
+     {
+        WRN("path '%s' is not a technology!", path);
+        return NULL;
+     }
+
+   return technology;
+}
+
+/**
+ * Get property "Name" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * Name of this technology.
+ *
+ * @param technology path to get property
+ * @param name where to store the property value, must be a pointer
+ *        to string (const char *), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_technology_name_get(const E_Connman_Element *technology, const char **name)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(technology, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (technology, e_connman_prop_name, NULL, name);
+}
+
+/**
+ * Get property "Type" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The technology type (for example "ethernet" etc.)
+ *
+ * This information should only be used to determine
+ * advanced properties or showing the correct icon
+ * to the user.
+ *
+ * @param technology path to get property.
+ * @param type where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_technology_type_get(const E_Connman_Element *technology, const char **type)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(technology, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (technology, e_connman_prop_type, NULL, type);
+}
+
+/**
+ * Get property "State" value.
+ *
+ * If this property isn't found then @c EINA_FALSE is returned.
+ * If @c EINA_FALSE is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * The technology state information.
+ *
+ * Valid states are "offline", "available", "enabled",
+ * and "connected".
+ *
+ * @param technology path to get property.
+ * @param state where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_connman_technology_state_get(const E_Connman_Element *technology, const char **state)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(technology, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(state, EINA_FALSE);
+   return e_connman_element_property_get_stringshared
+             (technology, e_connman_prop_state, NULL, state);
+}
diff --git a/src/lib/dbus/E_DBus.h b/src/lib/dbus/E_DBus.h
new file mode 100644 (file)
index 0000000..bd00f44
--- /dev/null
@@ -0,0 +1,434 @@
+#ifndef E_DBUS_H
+#define E_DBUS_H
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+
+#ifdef _WIN32
+# ifdef interface
+#  undef interface
+# endif
+#endif
+
+#ifdef _WIN32
+# ifdef interface
+#  undef interface
+# endif
+# define DBUS_API_SUBJECT_TO_CHANGE
+#endif
+
+#include <dbus/dbus.h>
+#include <Eina.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_EDBUS_BUILD
+#  ifdef DLL_EXPORT
+#   define EAPI __declspec(dllexport)
+#  else
+#   define EAPI
+#  endif /* ! DLL_EXPORT */
+# else
+#  define EAPI __declspec(dllimport)
+# endif /* ! EFL_EDBUS_BUILD */
+#else
+# ifdef __GNUC__
+#  if __GNUC__ >= 4
+#   define EAPI __attribute__ ((visibility("default")))
+#  else
+#   define EAPI
+#  endif
+# else
+#  define EAPI
+# endif
+#endif
+
+/**
+ * @mainpage EDbus
+ *
+ * @section edbus_intro_sec Introduction
+ *
+ * EDbus is a wrapper around the
+ * <a href="http://www.freedesktop.org/wiki/Software/dbus">dbus</a>
+ * library, which is a message bus system. It also implements a set of
+ * specifications using dbus as interprocess communication.
+ *
+ * @section edbus_modules_sec Modules
+ *
+ * @li @ref EDbus_Group Wrapper around the dbus library, which
+ * implementent an inter-process communication (IPC) system for
+ * software applications to communicate with one another.
+ * @li @ref EBluez_Group Implementation of the <a
+ * href="http://www.bluez.org/">BlueZ</a> specifications, for wireless
+ * communications with Bleutooth devices.
+ * @li @ref EConnman_Group Implementation of the <a
+ * href="http://connman.net/">connman</a> specifications, which
+ * manages internet connections running the Linux operating system.
+ * @li @ref EHal_Group Implementation of the <a
+ * href="http://www.freedesktop.org/wiki/Software/hal">HAL</a>
+ * specifications, which is a (software) layer between the hardware
+ * devices of a computer and the softwares that run on that
+ * computer (Hardware Abstraction Layer). HAL is deprecated, in favor
+ * of DeviceKit.
+ * @li @ref ENotify_Group To de described.
+ * @li @ref EOfono_Group Implementation of the <a
+ * href="http://ofono.org/">ofono</a> specifications, which is an
+ * interface for mobile telephony applications.
+ * @li @ref EUkit_Group Implementation of the <a
+ * href="http://freedesktop.org/wiki/Software/DeviceKit">DeviceKit</a>
+ * specifications, which is, like HAL, an Hardware Abstraction
+ * Layer. DeviceKit is a replacement of the deprecated HAL system. It
+ * has two submodules: UDisks, which manipulate storage devices, and
+ * UPower, which manage power devices.
+ */
+
+/**
+ * @defgroup EDbus_Group EDbus
+ *
+ * @{
+ */
+
+#define E_DBUS_FDO_BUS "org.freedesktop.DBus"
+#define E_DBUS_FDO_PATH "/org/freedesktop/DBus"
+#define E_DBUS_FDO_INTERFACE E_DBUS_FDO_BUS
+#define E_DBUS_FDO_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define E_DBUS_VERSION_MAJOR 1
+#define E_DBUS_VERSION_MINOR 7
+
+   typedef struct _E_DBus_Version
+     {
+        int major;
+        int minor;
+        int micro;
+        int revision;
+     } E_DBus_Version;
+
+   EAPI extern E_DBus_Version *e_dbus_version;
+
+   EAPI extern int E_DBUS_DOMAIN_GLOBAL;
+   EAPI extern int E_DBUS_EVENT_SIGNAL;
+
+   typedef struct E_DBus_Connection E_DBus_Connection;
+   typedef struct E_DBus_Object E_DBus_Object;
+   typedef struct E_DBus_Interface E_DBus_Interface;
+   typedef struct E_DBus_Signal_Handler E_DBus_Signal_Handler;
+
+   typedef DBusMessage *(* E_DBus_Method_Cb)(E_DBus_Object *obj, DBusMessage *message);
+   typedef void (*E_DBus_Method_Return_Cb) (void *data, DBusMessage *msg, DBusError *error);
+   typedef void (*E_DBus_Signal_Cb) (void *data, DBusMessage *msg);
+
+   typedef void (*E_DBus_Object_Property_Get_Cb) (E_DBus_Object *obj, const char *property, int *type, void **value);
+   typedef int  (*E_DBus_Object_Property_Set_Cb) (E_DBus_Object *obj, const char *property, int type, void *value);
+
+/**
+ * A callback function for a DBus call
+ * @param user_data the data passed in to the method call
+ * @param event_data a struct containing the return data.
+ */
+   typedef void (*E_DBus_Callback_Func) (void *user_data, void *method_return, DBusError *error);
+   typedef void *(*E_DBus_Unmarshal_Func) (DBusMessage *msg, DBusError *err);
+   typedef void (*E_DBus_Free_Func) (void *data);
+
+   typedef struct E_DBus_Callback E_DBus_Callback;
+
+
+/**
+ * @brief Initialize e_dbus
+ */
+EAPI int e_dbus_init(void);
+
+/**
+ * Shutdown e_dbus.
+ */
+EAPI int e_dbus_shutdown(void);
+
+/* setting up the connection */
+
+/**
+ * Retrieve a connection to the bus and integrate it with the ecore main loop.
+ * @param type the type of bus to connect to, e.g. DBUS_BUS_SYSTEM or DBUS_BUS_SESSION
+ */
+EAPI E_DBus_Connection *e_dbus_bus_get(DBusBusType type);
+
+   EAPI void e_dbus_connection_ref(E_DBus_Connection *conn);
+
+/**
+ * Integrate a DBus connection with the ecore main loop
+ *
+ * @param conn - a dbus connection
+ */
+EAPI E_DBus_Connection *e_dbus_connection_setup(DBusConnection *conn);
+
+/**
+ * Close out a connection retrieved with e_dbus_bus_get()
+ * @param conn the connection to close
+ */
+EAPI void e_dbus_connection_close(E_DBus_Connection *conn);
+
+/* receiving method calls */
+   EAPI E_DBus_Interface *e_dbus_interface_new(const char *interface);
+   EAPI void e_dbus_interface_ref(E_DBus_Interface *iface);
+   EAPI void e_dbus_interface_unref(E_DBus_Interface *iface);
+   EAPI void e_dbus_object_interface_attach(E_DBus_Object *obj, E_DBus_Interface *iface);
+   EAPI void e_dbus_object_interface_detach(E_DBus_Object *obj, E_DBus_Interface *iface);
+
+/**
+ * Add a method to an object
+ *
+ * @param iface the E_DBus_Interface to which this method belongs
+ * @param member the name of the method
+ * @param signature  an optional message signature. if provided, then messages
+ *                   with invalid signatures will be automatically rejected
+ *                   (an Error response will be sent) and introspection data
+ *                   will be available.
+ *
+ * @return 1 if successful, 0 if failed (e.g. no memory)
+ */
+EAPI int e_dbus_interface_method_add(E_DBus_Interface *iface, const char *member, const char *signature, const char *reply_signature, E_DBus_Method_Cb func);
+
+/**
+ * Add a signal to an object
+ *
+ * @param iface the E_DBus_Interface to which this signal belongs
+ * @param name  the name of the signal
+ * @param signature  an optional message signature.
+ *
+ * @return 1 if successful, 0 if failed (e.g. no memory)
+ */
+EAPI int e_dbus_interface_signal_add(E_DBus_Interface *iface, const char *name, const char *signature);
+
+/**
+ * Add a dbus object.
+ *
+ * @param conn the connection on with the object should listen
+ * @param object_path a unique string identifying an object (e.g. org/enlightenment/WindowManager
+ * @param data custom data to set on the object (retrievable via
+ *             e_dbus_object_data_get())
+ */
+EAPI E_DBus_Object *e_dbus_object_add(E_DBus_Connection *conn, const char *object_path, void *data);
+
+/**
+ * Free a dbus object
+ *
+ * @param obj the object to free
+ */
+EAPI void e_dbus_object_free(E_DBus_Object *obj);
+
+/**
+ * @brief Fetch the data pointer for a dbus object
+ * @param obj the dbus object
+ */
+EAPI void *e_dbus_object_data_get(E_DBus_Object *obj);
+
+/**
+ * @brief Get the dbus connection of a dbus object
+ * @param obj the dbus object
+ */
+EAPI E_DBus_Connection *e_dbus_object_conn_get(E_DBus_Object *obj);
+
+/**
+ * @brief Get the path of a dbus object
+ * @param obj the dbus object
+ */
+EAPI const char *e_dbus_object_path_get(E_DBus_Object *obj);
+
+/**
+ * @brief Get the interfaces of a dbus object
+ * @param obj the dbus object
+ */
+EAPI const Eina_List *e_dbus_object_interfaces_get(E_DBus_Object *obj);
+
+/**
+ * @brief Sets the callback to fetch properties from an object
+ * @param obj the object
+ * @param func the callback
+ */
+EAPI void e_dbus_object_property_get_cb_set(E_DBus_Object *obj, E_DBus_Object_Property_Get_Cb func);
+
+/**
+ * @brief Sets the callback to set properties on an object
+ * @param obj the object
+ * @param func the callback
+ */
+EAPI void e_dbus_object_property_set_cb_set(E_DBus_Object *obj, E_DBus_Object_Property_Set_Cb func);
+
+
+/* sending method calls */
+
+/**
+ * @brief Send a DBus message with callbacks
+ * @param conn The DBus connection
+ * @param msg  The message to send
+ * @param cb_return A callback function for returns (only used if @a msg is a method-call)
+ * @param timeout   A timeout in milliseconds, after which a synthetic error will be generated
+ * @param data custom data to pass in to the callback
+ * @return a DBusPendingCall that can be used to cancel the current call
+ */
+EAPI DBusPendingCall *e_dbus_message_send(E_DBus_Connection *conn, DBusMessage *msg, E_DBus_Method_Return_Cb cb_return, int timeout, void *data);
+
+   EAPI DBusPendingCall *e_dbus_method_call_send(E_DBus_Connection *conn, DBusMessage *msg, E_DBus_Unmarshal_Func unmarshal_func, E_DBus_Callback_Func cb_func, E_DBus_Free_Func free_func, int timeout, void *data);
+
+
+/* signal receiving */
+
+/**
+ * Add a signal handler
+ *
+ * @param conn the dbus connection
+ * @param sender name of the signal's sender
+ * @param path the object path of the signal's sender
+ * @param interface the signal's interface
+ * @param member the signal's name
+ * @param cb_signal a callback to call when the signal is received
+ * @param data custom data to pass in to the callback
+ */
+EAPI E_DBus_Signal_Handler *e_dbus_signal_handler_add(E_DBus_Connection *conn, const char *sender, const char *path, const char *interface, const char *member, E_DBus_Signal_Cb cb_signal, void *data);
+
+/**
+ * Delete a signal handler
+ *
+ * @param conn the dbus connection
+ * @param sh the handler to delete
+ */
+EAPI void e_dbus_signal_handler_del(E_DBus_Connection *conn, E_DBus_Signal_Handler *sh);
+
+/* standard dbus method calls */
+
+   EAPI DBusPendingCall *e_dbus_request_name(E_DBus_Connection *conn, const char *name,
+                                            unsigned int flags,
+                                            E_DBus_Method_Return_Cb cb_return,
+                                            const void *data);
+   EAPI DBusPendingCall *e_dbus_release_name(E_DBus_Connection *conn, const char *name,
+                                            E_DBus_Method_Return_Cb cb_return,
+                                            const void *data);
+
+   EAPI DBusPendingCall *e_dbus_get_name_owner(E_DBus_Connection *conn, const char *name,
+                                              E_DBus_Method_Return_Cb cb_return,
+                                              const void *data);
+   EAPI DBusPendingCall *e_dbus_list_names(E_DBus_Connection *conn,
+                                          E_DBus_Method_Return_Cb cb_return,
+                                          const void *data);
+   EAPI DBusPendingCall *e_dbus_list_activatable_names(E_DBus_Connection *conn,
+                                                      E_DBus_Method_Return_Cb cb_return,
+                                                      const void *data);
+   EAPI DBusPendingCall *e_dbus_name_has_owner(E_DBus_Connection *conn, const char *name,
+                                              E_DBus_Method_Return_Cb cb_return,
+                                              const void *data);
+   EAPI DBusPendingCall *e_dbus_start_service_by_name(E_DBus_Connection *conn, const char *name, unsigned int flags,
+                                                     E_DBus_Method_Return_Cb cb_return,
+                                                     const void *data);
+
+/* standard methods calls on objects */
+
+/**
+ * Calls the Introspect method on a given bus and object path.
+ * @param conn The dbus connection to use
+ * @param bus The bus to call the method on
+ * @param object_path The path of the bus to call on
+ * @param cb_return The callback to call on reply from dbus
+ * @param data The data to associate with the callback
+ * @return A pending dbus call
+ */
+EAPI DBusPendingCall *e_dbus_introspect(E_DBus_Connection *conn, const char *bus,
+       const char *object_path, E_DBus_Method_Return_Cb cb_return, const void *data);
+
+/**
+ * Ping the dbus peer
+ *
+ * @param conn the dbus connection
+ * @param destination the bus name that the object is on
+ * @param path the object path
+ * @param cb_return a callback for a successful return
+ * @param data data to pass to the callbacks
+ */
+EAPI DBusPendingCall *e_dbus_peer_ping(E_DBus_Connection *conn, const char *destination,
+                                         const char *path, E_DBus_Method_Return_Cb cb_return,
+                                         const void *data);
+
+/**
+ * Get the UUID of the peer
+ *
+ * @param conn the dbus connection
+ * @param destination the bus name that the object is on
+ * @param path the object path
+ * @param cb_return a callback for a successful return
+ * @param data data to pass to the callbacks
+ */
+EAPI DBusPendingCall *e_dbus_peer_get_machine_id(E_DBus_Connection *conn,
+                                                   const char *destination, const char *path,
+                                                   E_DBus_Method_Return_Cb cb_return,
+                                                   const void *data);
+   EAPI DBusPendingCall *e_dbus_properties_get_all(E_DBus_Connection *conn, const char *destination,
+                                                  const char *path, const char *interface,
+                                                  E_DBus_Method_Return_Cb cb_return,
+                                                  const void *data);
+
+/**
+ * Get the value of a property on an object
+ *
+ * @param conn the dbus connection
+ * @param destination the bus name that the object is on
+ * @param path the object path
+ * @param interface the interface name of the property
+ * @param property the name of the property
+ * @param cb_return a callback for a successful return
+ * @param data data to pass to the callbacks
+ */
+EAPI DBusPendingCall *e_dbus_properties_get(E_DBus_Connection *conn, const char *destination,
+                                              const char *path, const char *interface,
+                                              const char *property,
+                                              E_DBus_Method_Return_Cb cb_return,
+                                              const void *data);
+
+/**
+ * Set the value of a property on an object
+ *
+ * @param conn the dbus connection
+ * @param destination the bus name that the object is on
+ * @param path the object path
+ * @param interface the interface name of the property
+ * @param property the name of the property
+ * @param value_type the type of the property's value
+ * @param value a pointer to the value
+ * @param cb_return a callback for a successful return
+ * @param data data to pass to the callbacks
+ */
+EAPI DBusPendingCall *e_dbus_properties_set(E_DBus_Connection *conn, const char *destination,
+                                              const char *path, const char *interface,
+                                              const char *property, int value_type,
+                                              const void *value, E_DBus_Method_Return_Cb cb_return,
+                                              const void *data);
+
+
+/**
+ * @brief Create a callback structure
+ * @param cb_func the callback function
+ * @param user_data data to pass to the callback
+ */
+EAPI E_DBus_Callback *e_dbus_callback_new(E_DBus_Callback_Func cb_func, E_DBus_Unmarshal_Func unmarshal_func, E_DBus_Free_Func free_func, void *user_data);
+
+/**
+ * @brief Free a callback structure
+ * @param callback the callback to free
+ */
+EAPI void e_dbus_callback_free(E_DBus_Callback *callback);
+   EAPI void e_dbus_callback_call(E_DBus_Callback *cb, void *data, DBusError *error);
+   EAPI void *e_dbus_callback_unmarshal(E_DBus_Callback *cb, DBusMessage *msg, DBusError *err);
+   EAPI void e_dbus_callback_return_free(E_DBus_Callback *callback, void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/src/lib/dbus/Makefile.am b/src/lib/dbus/Makefile.am
new file mode 100644 (file)
index 0000000..e838d03
--- /dev/null
@@ -0,0 +1,26 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+@EFL_EDBUS_BUILD@ \
+@DBUS_VERSION_CFLAGS@ \
+@EDBUS_CFLAGS@
+
+
+lib_LTLIBRARIES = libedbus.la
+includes_HEADERS = E_DBus.h
+includesdir = $(includedir)/e_dbus-@VMAJ@
+
+libedbus_la_SOURCES = \
+e_dbus.c \
+e_dbus_message.c \
+e_dbus_methods.c \
+e_dbus_interfaces.c \
+e_dbus_object.c \
+e_dbus_util.c \
+e_dbus_signal.c
+
+
+libedbus_la_LIBADD = @EDBUS_LIBS@
+libedbus_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@
+
+EXTRA_DIST = e_dbus_private.h
diff --git a/src/lib/dbus/e_dbus.c b/src/lib/dbus/e_dbus.c
new file mode 100644 (file)
index 0000000..5f0ade6
--- /dev/null
@@ -0,0 +1,620 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "e_dbus_private.h"
+
+static E_DBus_Version _version = { VMAJ, VMIN, VMIC, VREV };
+EAPI E_DBus_Version *e_dbus_version = &_version;
+
+#define NUM_BUS_TYPES 3
+
+/*
+ * TODO: 
+ *  listen for disconnected signal and clean up?
+ */
+int _e_dbus_log_dom = -1;
+static int connection_slot = -1;
+
+static int _edbus_init_count = 0;
+static int close_connection = 0;
+EAPI int E_DBUS_EVENT_SIGNAL = 0;
+
+static E_DBus_Connection *shared_connections[2] = {NULL, NULL};
+
+typedef struct E_DBus_Handler_Data E_DBus_Handler_Data;
+typedef struct E_DBus_Timeout_Data E_DBus_Timeout_Data;
+
+
+struct E_DBus_Handler_Data
+{
+  int fd;
+  Ecore_Fd_Handler *fd_handler;
+  E_DBus_Connection *cd;
+  DBusWatch *watch;
+  int enabled;
+};
+
+struct E_DBus_Timeout_Data
+{
+  Ecore_Timer *handler;
+  DBusTimeout *timeout;
+  E_DBus_Connection *cd;
+  int interval;
+};
+
+static Eina_Bool e_dbus_idler(void *data);
+
+static void
+e_dbus_fd_handler_del(E_DBus_Handler_Data *hd)
+{
+  if (!hd->fd_handler) return;
+
+  DBG("handler disabled");
+  hd->cd->fd_handlers = eina_list_remove(hd->cd->fd_handlers, hd->fd_handler);
+  ecore_main_fd_handler_del(hd->fd_handler);
+  hd->fd_handler = NULL;
+}
+
+static Eina_Bool
+e_dbus_fd_handler(void *data, Ecore_Fd_Handler *fd_handler)
+{
+  E_DBus_Handler_Data *hd;
+  unsigned int condition = 0;
+
+  DBG("fd handler (%p)!", fd_handler);
+
+  hd = data;
+
+  if (!hd->enabled)
+    {
+       e_dbus_fd_handler_del(hd);
+       return ECORE_CALLBACK_CANCEL;
+    }
+  if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) condition |= DBUS_WATCH_READABLE;
+  if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE)) condition |= DBUS_WATCH_WRITABLE;
+  if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR)) condition |= DBUS_WATCH_ERROR;
+  DBG("fdh || READ: %d, WRITE: %d",
+      (condition & DBUS_WATCH_READABLE) == DBUS_WATCH_READABLE,
+      (condition & DBUS_WATCH_WRITABLE) == DBUS_WATCH_WRITABLE);
+
+  if (condition & DBUS_WATCH_ERROR) DBG("DBUS watch error");
+  dbus_watch_handle(hd->watch, condition);
+  hd = NULL;
+
+  return ECORE_CALLBACK_RENEW;
+}
+
+static void
+e_dbus_fd_handler_add(E_DBus_Handler_Data *hd)
+{
+  unsigned int dflags;
+  Ecore_Fd_Handler_Flags eflags;
+  Eina_List *l;
+  Ecore_Fd_Handler *fdh;
+
+  if (hd->fd_handler) return;
+  dflags = dbus_watch_get_flags(hd->watch);
+  eflags = ECORE_FD_ERROR;
+  if (dflags & DBUS_WATCH_READABLE) eflags |= ECORE_FD_READ;
+  if (dflags & DBUS_WATCH_WRITABLE) eflags |= ECORE_FD_WRITE;
+
+  EINA_LIST_FOREACH(hd->cd->fd_handlers, l, fdh)
+    {
+       if (ecore_main_fd_handler_fd_get(fdh) == hd->fd) return;
+    }
+
+  DBG("fd handler add (%d)", hd->fd);
+  hd->fd_handler = ecore_main_fd_handler_add(hd->fd,
+                                             eflags,
+                                             e_dbus_fd_handler,
+                                             hd,
+                                             NULL,
+                                             NULL);
+
+  hd->cd->fd_handlers = eina_list_append(hd->cd->fd_handlers, hd->fd_handler);
+}
+
+
+static void
+e_dbus_handler_data_free(void *data)
+{
+  E_DBus_Handler_Data *hd = data;
+  
+  DBG("e_dbus_handler_data_free");
+  if (hd->fd_handler)
+  {
+    hd->cd->fd_handlers = eina_list_remove(hd->cd->fd_handlers, hd->fd_handler);
+    ecore_main_fd_handler_del(hd->fd_handler);
+  }
+  free(hd);
+}
+
+static void
+e_dbus_connection_data_watch_add(E_DBus_Connection *cd, DBusWatch *watch)
+{
+  E_DBus_Handler_Data *hd;
+
+  hd = calloc(1, sizeof(E_DBus_Handler_Data));
+  dbus_watch_set_data(watch, hd, e_dbus_handler_data_free);
+  hd->cd = cd;
+  hd->watch = watch;
+
+  hd->enabled = dbus_watch_get_enabled(watch);
+#if (DBUS_VERSION_MAJOR == 1 && DBUS_VERSION_MINOR == 1 && DBUS_VERSION_MICRO>= 1) || (DBUS_VERSION_MAJOR == 1 && DBUS_VERSION_MINOR > 1) || (DBUS_VERSION_MAJOR > 1)
+  hd->fd = dbus_watch_get_unix_fd(hd->watch);
+#else
+  hd->fd = dbus_watch_get_fd(hd->watch);
+#endif
+  DBG("watch add (enabled: %d)", hd->enabled);
+  if (hd->enabled) e_dbus_fd_handler_add(hd);
+}
+
+static E_DBus_Connection *
+e_dbus_connection_new(DBusConnection *conn)
+{
+  E_DBus_Connection *cd;
+  const char *conn_name;
+
+  cd = calloc(1, sizeof(E_DBus_Connection));
+  if (!cd) return NULL;
+
+  cd->conn = conn;
+  conn_name = dbus_bus_get_unique_name(conn);
+  if (conn_name)
+  {
+    DBG("Connected! Name: %s", conn_name);
+    cd->conn_name = strdup(conn_name);
+  }
+  else
+    DBG("Not connected");
+
+  cd->shared_type = (unsigned int)-1;
+  cd->fd_handlers = NULL;
+  cd->timeouts = NULL;
+
+  return cd;
+}
+
+static void
+e_dbus_connection_free(void *data)
+{
+  E_DBus_Connection *cd = data;
+  Ecore_Fd_Handler *fd_handler;
+  Ecore_Timer *timer;
+  DBG("e_dbus_connection free!");
+
+  EINA_LIST_FREE(cd->fd_handlers, fd_handler)
+    ecore_main_fd_handler_del(fd_handler);
+
+  EINA_LIST_FREE(cd->timeouts, timer)
+    ecore_timer_del(timer);
+
+  if (cd->shared_type != (unsigned int)-1)
+    shared_connections[cd->shared_type] = NULL;
+
+  e_dbus_signal_handlers_free_all(cd);
+
+  if (cd->conn_name) free(cd->conn_name);
+
+  if (cd->idler) ecore_idler_del(cd->idler);
+
+  free(cd);
+}
+
+static void
+cb_dispatch_status(DBusConnection *conn __UNUSED__, DBusDispatchStatus new_status, void *data)
+{
+  E_DBus_Connection *cd;
+
+  DBG("dispatch status: %d!", new_status);
+  cd = data;
+
+  if (new_status == DBUS_DISPATCH_DATA_REMAINS && !cd->idler)
+     cd->idler = ecore_idler_add(e_dbus_idler, cd);
+  else if (new_status != DBUS_DISPATCH_DATA_REMAINS && cd->idler) 
+    {
+       ecore_idler_del(cd->idler);
+       cd->idler = NULL;
+    }
+}
+
+static Eina_Bool
+e_dbus_timeout_handler(void *data)
+{
+  E_DBus_Timeout_Data *td;
+
+  td = data;
+
+  if (!dbus_timeout_get_enabled(td->timeout))
+  {
+    DBG("timeout_handler (not enabled, ending)");
+    td->handler = NULL;
+    return ECORE_CALLBACK_CANCEL;
+  }
+
+  DBG("timeout handler!");
+  dbus_timeout_handle(td->timeout);
+  return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+e_dbus_timeout_data_free(void *timeout_data)
+{
+  E_DBus_Timeout_Data *td = timeout_data;
+  DBG("e_dbus_timeout_data_free");
+  if (td->handler) ecore_timer_del(td->handler);
+  free(td);
+}
+
+static dbus_bool_t 
+cb_timeout_add(DBusTimeout *timeout, void *data)
+{
+  E_DBus_Connection *cd;
+  E_DBus_Timeout_Data *td;
+  
+  cd = data;
+  DBG("timeout add!");
+  td = calloc(1, sizeof(E_DBus_Timeout_Data));
+  td->cd = cd;
+  dbus_timeout_set_data(timeout, (void *)td, e_dbus_timeout_data_free);
+
+  td->interval = dbus_timeout_get_interval(timeout);
+  td->timeout = timeout;
+
+  if (dbus_timeout_get_enabled(timeout)) td->handler = ecore_timer_add(td->interval, e_dbus_timeout_handler, td);
+  td->cd->timeouts = eina_list_append(td->cd->timeouts, td->handler);
+
+  return true;
+}
+
+static void
+cb_timeout_del(DBusTimeout *timeout, void *data __UNUSED__)
+{
+  E_DBus_Timeout_Data *td;
+  DBG("timeout del!");
+
+  td = (E_DBus_Timeout_Data *)dbus_timeout_get_data(timeout);
+
+  if (td->handler) 
+  {
+    td->cd->timeouts = eina_list_remove(td->cd->timeouts, td->handler);
+    ecore_timer_del(td->handler);
+    td->handler = NULL;
+  }
+
+  /* Note: timeout data gets freed when the timeout itself is freed by dbus */
+}
+
+static void
+cb_timeout_toggle(DBusTimeout *timeout, void *data __UNUSED__)
+{
+  E_DBus_Timeout_Data *td;
+  DBG("timeout toggle!");
+
+  td = (E_DBus_Timeout_Data *)dbus_timeout_get_data(timeout);
+
+  if (dbus_timeout_get_enabled(td->timeout))
+  {
+    td->interval = dbus_timeout_get_interval(timeout);
+    td->handler = ecore_timer_add(td->interval, e_dbus_timeout_handler, td);
+  }
+  else
+  {
+    ecore_timer_del(td->handler);
+    td->handler = NULL;
+  }
+
+
+}
+
+static dbus_bool_t 
+cb_watch_add(DBusWatch *watch, void *data)
+{
+  E_DBus_Connection *cd;
+  cd = data;
+
+  DBG("cb_watch_add");
+  e_dbus_connection_data_watch_add(cd, watch);
+
+  return true;
+}
+
+static void
+cb_watch_del(DBusWatch *watch, void *data __UNUSED__)
+{
+  E_DBus_Handler_Data *hd;
+
+  DBG("cb_watch_del");
+  hd = (E_DBus_Handler_Data *)dbus_watch_get_data(watch);
+  e_dbus_fd_handler_del(hd);
+}
+
+static void
+cb_watch_toggle(DBusWatch *watch, void *data __UNUSED__)
+{
+  E_DBus_Handler_Data *hd;
+
+  DBG("cb_watch_toggle");
+  hd = dbus_watch_get_data(watch);
+
+  if (!hd) return;
+
+  hd->enabled = dbus_watch_get_enabled(watch);
+
+  INFO("watch %p is %sabled", hd, hd->enabled ? "en" : "dis");
+  if (hd->enabled) e_dbus_fd_handler_add(hd);
+  else e_dbus_fd_handler_del(hd);
+}
+
+static void
+e_dbus_message_free(void *data __UNUSED__, void *message)
+{
+  dbus_message_unref(message);
+}
+
+static DBusHandlerResult
+e_dbus_filter(DBusConnection *conn __UNUSED__, DBusMessage *message, void *user_data)
+{
+  E_DBus_Connection *cd = user_data;
+  DBG("-----------------");
+  DBG("Message!");
+
+  DBG("type: %s", dbus_message_type_to_string(dbus_message_get_type(message)));
+  DBG("path: %s", dbus_message_get_path(message));
+  DBG("interface: %s", dbus_message_get_interface(message));
+  DBG("member: %s", dbus_message_get_member(message));
+  DBG("sender: %s", dbus_message_get_sender(message));
+
+  switch (dbus_message_get_type(message))
+  {
+    case DBUS_MESSAGE_TYPE_METHOD_CALL:
+      DBG("signature: %s", dbus_message_get_signature(message));
+      break;
+    case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+      DBG("reply serial %d", dbus_message_get_reply_serial(message));
+      break;
+    case DBUS_MESSAGE_TYPE_ERROR:
+      DBG("error: %s", dbus_message_get_error_name(message));
+      break;
+    case DBUS_MESSAGE_TYPE_SIGNAL:
+      dbus_message_ref(message);
+      if (cd->signal_dispatcher) cd->signal_dispatcher(cd, message);
+      ecore_event_add(E_DBUS_EVENT_SIGNAL, message, e_dbus_message_free, NULL);
+      break;
+    default:
+      break;
+  }
+  DBG("-----------------");
+
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+int e_dbus_idler_active = 0;
+
+static Eina_Bool
+e_dbus_idler(void *data)
+{
+  E_DBus_Connection *cd;
+  cd = data;
+
+  if (DBUS_DISPATCH_COMPLETE == dbus_connection_get_dispatch_status(cd->conn))
+  {
+    DBG("done dispatching!");
+    cd->idler = NULL;
+    return ECORE_CALLBACK_CANCEL;
+  }
+  e_dbus_idler_active++;
+  dbus_connection_ref(cd->conn);
+  DBG("dispatch()");
+  dbus_connection_dispatch(cd->conn);
+  dbus_connection_unref(cd->conn);
+  e_dbus_idler_active--;
+  e_dbus_signal_handlers_clean(cd);
+  if (!e_dbus_idler_active && close_connection)
+  {
+    do
+    {
+      e_dbus_connection_close(cd);
+    } while (--close_connection);
+  }
+  return ECORE_CALLBACK_RENEW;
+}
+
+EAPI E_DBus_Connection *
+e_dbus_bus_get(DBusBusType type)
+{
+  DBusError err;
+  E_DBus_Connection *econn;
+  DBusConnection *conn;
+
+  /* each app only needs a single connection to either bus */
+  if (type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION)
+  {
+    if (shared_connections[type]) 
+    {
+      e_dbus_connection_ref(shared_connections[type]);
+      return shared_connections[type];
+    }
+  }
+
+  dbus_error_init(&err);
+
+  conn = dbus_bus_get_private(type, &err);
+  if (dbus_error_is_set(&err))
+  {
+    ERR("Error connecting to bus: %s", err.message);
+    dbus_error_free(&err);
+    return NULL;
+  }
+
+  econn = e_dbus_connection_setup(conn);
+  if (!econn)
+  {
+    ERR("Error setting up dbus connection.");
+    dbus_connection_close(conn);
+    dbus_connection_unref(conn);
+    return NULL;
+  }
+
+  if (type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION)
+  {
+    econn->shared_type = type;
+    shared_connections[type] = econn;
+  }
+  dbus_error_free(&err);
+  e_dbus_connection_ref(econn);
+  return econn;
+}
+
+EAPI E_DBus_Connection *
+e_dbus_connection_setup(DBusConnection *conn)
+{
+  E_DBus_Connection *cd;
+
+  cd = e_dbus_connection_new(conn);
+  if (!cd) return NULL;
+
+  /* connection_setup */
+  dbus_connection_set_exit_on_disconnect(cd->conn, EINA_FALSE);
+  dbus_connection_allocate_data_slot(&connection_slot);
+
+  dbus_connection_set_data(cd->conn, connection_slot, (void *)cd, e_dbus_connection_free);
+  dbus_connection_set_watch_functions(cd->conn,
+                                      cb_watch_add,
+                                      cb_watch_del,
+                                      cb_watch_toggle,
+                                      cd,
+                                      NULL);
+
+  dbus_connection_set_timeout_functions(cd->conn,
+                                      cb_timeout_add,
+                                      cb_timeout_del,
+                                      cb_timeout_toggle,
+                                      cd,
+                                      NULL);
+
+  dbus_connection_set_dispatch_status_function(cd->conn, cb_dispatch_status, cd, NULL);
+  dbus_connection_add_filter(cd->conn, e_dbus_filter, cd, NULL);
+
+  cb_dispatch_status(cd->conn, dbus_connection_get_dispatch_status(cd->conn), cd);
+
+  return cd;
+}
+
+
+EAPI void
+e_dbus_connection_close(E_DBus_Connection *conn)
+{
+  if (!conn) return;
+  DBG("e_dbus_connection_close");
+
+  if (e_dbus_idler_active)
+  {
+    close_connection++;
+    return;
+  }
+  if (--(conn->refcount) != 0) return;
+
+  dbus_connection_free_data_slot(&connection_slot);
+  dbus_connection_remove_filter(conn->conn, e_dbus_filter, conn);
+  dbus_connection_set_watch_functions (conn->conn,
+                                       NULL,
+                                       NULL,
+                                       NULL,
+                                       NULL, NULL);
+
+  dbus_connection_set_timeout_functions (conn->conn,
+                                         NULL,
+                                         NULL,
+                                         NULL,
+                                         NULL, NULL);
+
+  dbus_connection_set_dispatch_status_function (conn->conn, NULL, NULL, NULL);
+
+  /* Idler functin must be cancelled when dbus connection is  unreferenced */
+  if (conn->idler)
+    {
+      ecore_idler_del(conn->idler);
+      conn->idler = NULL;
+    }
+
+  dbus_connection_close(conn->conn);
+  dbus_connection_unref(conn->conn);
+
+  // Note: the E_DBus_Connection gets freed when the dbus_connection is cleaned up by the previous unref
+}
+
+EAPI void
+e_dbus_connection_ref(E_DBus_Connection *conn)
+{
+  EINA_SAFETY_ON_NULL_RETURN(conn);
+  conn->refcount++;
+}
+
+DBusConnection *
+e_dbus_connection_dbus_connection_get(E_DBus_Connection *conn)
+{
+  EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+  return conn->conn;
+}
+
+EAPI int
+e_dbus_init(void)
+{
+  if (++_edbus_init_count != 1)
+    return _edbus_init_count;
+  
+  if (!eina_init())
+    {
+      fprintf(stderr,"E-dbus: Enable to initialize eina\n");
+      return --_edbus_init_count;
+    }
+
+  _e_dbus_log_dom = eina_log_domain_register("e_dbus", E_DBUS_COLOR_DEFAULT);
+  if (_e_dbus_log_dom < 0)
+    {
+      EINA_LOG_ERR("Unable to create an 'e_dbus' log domain");
+      eina_shutdown();
+      return --_edbus_init_count;
+    }
+  if (!ecore_init())
+    {
+      ERR("E-dbus: Unable to initialize ecore");
+      eina_log_domain_unregister(_e_dbus_log_dom);
+      _e_dbus_log_dom = -1;
+      eina_shutdown();
+      return --_edbus_init_count;
+    }
+
+
+  E_DBUS_EVENT_SIGNAL = ecore_event_type_new();
+  e_dbus_object_init();
+
+  return _edbus_init_count;
+}
+
+EAPI int
+e_dbus_shutdown(void)
+{
+   if (_edbus_init_count <= 0)
+     {
+        EINA_LOG_ERR("Init count not greater than 0 in shutdown.");
+        return 0;
+     }
+   if (--_edbus_init_count)
+    return _edbus_init_count;
+
+  e_dbus_object_shutdown();
+  ecore_shutdown();
+  eina_log_domain_unregister(_e_dbus_log_dom);
+  _e_dbus_log_dom = -1;
+  eina_shutdown();
+
+  return _edbus_init_count;
+}
diff --git a/src/lib/dbus/e_dbus_interfaces.c b/src/lib/dbus/e_dbus_interfaces.c
new file mode 100644 (file)
index 0000000..161a180
--- /dev/null
@@ -0,0 +1,176 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "e_dbus_private.h"
+
+/*
+ * This file contains wrappers around the standard interfaces that
+ * objects on the bus should implement.
+ */
+
+static inline DBusPendingCall *
+_dbus_peer_call(E_DBus_Connection *conn, const char *method_name, const char *destination, const char *path, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+  DBusMessage *msg;
+  DBusPendingCall *ret;
+
+  msg = dbus_message_new_method_call
+    (destination, path, "org.freedesktop.DBus.Peer", method_name);
+  if (!msg)
+    {
+      ERR("E-dbus Error: failed to create message for method call: %s() at "
+           "\"%s\" at \"%s\"",
+           method_name, destination, path);
+       return NULL;
+    }
+
+  ret = e_dbus_message_send(conn, msg, cb_return, -1, (void *)data);
+  dbus_message_unref(msg);
+
+  if (!ret)
+    ERR("E-dbus Error: could not %s() \"%s\" at \"%s\".",
+         method_name, destination, path);
+  
+  return ret;
+}
+
+EAPI DBusPendingCall *
+e_dbus_peer_ping(E_DBus_Connection *conn, const char *destination, const char *path, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+   return _dbus_peer_call(conn, "Ping", destination, path, cb_return, data);
+}
+
+EAPI DBusPendingCall *
+e_dbus_peer_get_machine_id(E_DBus_Connection *conn, const char *destination, const char *path, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+   return _dbus_peer_call(conn, "GetMachineId", destination, path, cb_return, data);
+}
+
+static inline DBusMessage *
+_dbus_message_property_method_call(E_DBus_Connection *conn, const char *method_name, const char *destination, const char *path, const char *interface, const char *property)
+{
+  DBusMessage *msg;
+
+  if (!conn)
+    {
+      ERR("E-dbus Error: no connection for call of %s", method_name);
+       return NULL;
+    }
+
+  msg = dbus_message_new_method_call
+    (destination, path, E_DBUS_FDO_INTERFACE_PROPERTIES, method_name);
+  if (!msg)
+    {
+      ERR("E-dbus Error: failed to create message for method call: %s() at "
+           "\"%s\" at \"%s\"",
+           method_name, destination, path);
+      return NULL;
+    }
+
+  if (property)
+  {
+    dbus_message_append_args(msg, DBUS_TYPE_STRING, &interface,
+                            DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID);
+  }
+  else
+  {
+    dbus_message_append_args(msg, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID);
+  }
+
+  return msg;
+}
+
+EAPI DBusPendingCall *
+e_dbus_properties_get_all(E_DBus_Connection *conn, const char *destination, const char *path, const char *interface, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+  DBusMessage *msg;
+  DBusPendingCall *ret;
+
+  EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+  msg = _dbus_message_property_method_call
+    (conn, "GetAll", destination, path, interface, NULL);
+  if (!msg)
+    return NULL;
+  ret = e_dbus_message_send(conn, msg, cb_return, -1, (void *)data);
+  dbus_message_unref(msg);
+
+  if (!ret)
+    ERR("ERROR: failed to call GetAll() at \"%s\" at \"%s\"",
+         destination, path);
+
+  return ret;
+}
+
+EAPI DBusPendingCall *
+e_dbus_properties_get(E_DBus_Connection *conn, const char *destination, const char *path, const char *interface, const char *property, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+  DBusMessage *msg;
+  DBusPendingCall *ret;
+
+  EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+  msg = _dbus_message_property_method_call
+    (conn, "Get", destination, path, interface, property);
+  if (!msg)
+    return NULL;
+  ret = e_dbus_message_send(conn, msg, cb_return, -1, (void *)data);
+  dbus_message_unref(msg);
+
+  if (!ret)
+    ERR("E-dbus Error: failed to call Get() at \"%s\" at \"%s\"",
+         destination, path);
+
+  return ret;
+}
+
+EAPI DBusPendingCall *
+e_dbus_properties_set(E_DBus_Connection *conn, const char *destination, const char *path, const char *interface, const char *property, int value_type, const void *value, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+  DBusMessage *msg;
+  DBusMessageIter iter, sub;
+  DBusError err;
+  DBusPendingCall *ret;
+  char sig[2];
+
+  EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+  if (!dbus_type_is_basic(value_type))
+  {
+    if (cb_return)
+    {
+      dbus_error_init(&err);
+      dbus_set_error(&err, "org.enlightenment.DBus.InvalidType", "Only basic types may be set using e_dbus_properties_set()");
+      cb_return((void *)data, NULL, &err);
+
+    }
+    return NULL;
+  }
+
+  msg = _dbus_message_property_method_call
+    (conn, "Set", destination, path, interface, property);
+  if (!msg)
+    return NULL;
+
+  dbus_message_iter_init_append(msg, &iter);
+  sig[0] = value_type;
+  sig[1] = 0;
+  if (dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, sig, &sub))
+  {
+    dbus_message_iter_append_basic(&sub, value_type, value);
+    dbus_message_iter_close_container(&iter, &sub);
+  }
+  else
+  {
+    ERR("dbus_message_iter_open_container() failed");
+  }
+
+  ret = e_dbus_message_send(conn, msg, cb_return, -1, (void *)data);
+  dbus_message_unref(msg);
+
+  if (!ret)
+    ERR("E-dbus Error: failed to call Set() at \"%s\" at \"%s\"",
+         destination, path);
+
+  return ret;
+}
diff --git a/src/lib/dbus/e_dbus_message.c b/src/lib/dbus/e_dbus_message.c
new file mode 100644 (file)
index 0000000..d535ced
--- /dev/null
@@ -0,0 +1,122 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "e_dbus_private.h"
+
+typedef struct E_DBus_Pending_Call_Data E_DBus_Pending_Call_Data;
+struct E_DBus_Pending_Call_Data
+{
+  E_DBus_Method_Return_Cb cb_return;
+  void                   *data;
+};
+
+static void
+cb_pending(DBusPendingCall *pending, void *user_data)
+{
+  DBusMessage *msg;
+  DBusError err;
+  E_DBus_Pending_Call_Data *data = user_data;
+
+  if (!dbus_pending_call_get_completed(pending))
+  {
+    INFO("E-dbus: NOT COMPLETED");
+    free(data);
+    dbus_pending_call_unref(pending);
+    return;
+  }
+
+  dbus_error_init(&err);
+  msg = dbus_pending_call_steal_reply(pending);
+  if (!msg)
+  {
+    if (data->cb_return)
+    {
+      dbus_set_error(&err, "org.enlightenment.DBus.NoReply", "There was no reply to this method call.");
+      data->cb_return(data->data, NULL, &err);
+      dbus_error_free(&err);
+    }
+    return;
+  }
+
+  if (dbus_set_error_from_message(&err, msg))
+  {
+    if (data->cb_return)
+      data->cb_return(data->data, NULL, &err);
+    dbus_error_free(&err);
+  }
+  else
+  {
+    if (data->cb_return)
+      data->cb_return(data->data, msg, &err);
+  }
+
+  dbus_message_unref(msg);
+  dbus_pending_call_unref(pending);
+}
+
+
+EAPI DBusPendingCall *
+e_dbus_message_send(E_DBus_Connection *conn, DBusMessage *msg, E_DBus_Method_Return_Cb cb_return, int timeout, void *data)
+{
+  DBusPendingCall *pending;
+
+  EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+  if (!dbus_connection_send_with_reply(conn->conn, msg, &pending, timeout))
+    return NULL;
+
+  if (cb_return && pending)
+  {
+    E_DBus_Pending_Call_Data *pdata;
+
+    pdata = malloc(sizeof(E_DBus_Pending_Call_Data));
+    pdata->cb_return = cb_return;
+    pdata->data = data;
+
+    if (!dbus_pending_call_set_notify(pending, cb_pending, pdata, free))
+    {
+      free(pdata);
+      dbus_message_unref(msg);
+      dbus_pending_call_cancel(pending);
+      return NULL;
+    }
+  }
+
+  return pending;
+}
+
+static void
+cb_method_call(void *data, DBusMessage *msg, DBusError *err)
+{
+  E_DBus_Callback *cb = data;
+  void *method_return = NULL;
+  DBusError new_err;
+  if (!cb) return;
+
+  dbus_error_init(&new_err);
+  if (!dbus_error_is_set(err))
+    method_return = e_dbus_callback_unmarshal(cb, msg, &new_err);
+  else
+    dbus_move_error(err, &new_err);
+
+  e_dbus_callback_call(cb, method_return, &new_err);
+  e_dbus_callback_return_free(cb, method_return);
+
+  if (dbus_error_is_set(&new_err))
+    dbus_error_free(&new_err);
+
+  e_dbus_callback_free(cb);
+}
+
+EAPI DBusPendingCall *
+e_dbus_method_call_send(E_DBus_Connection *conn, DBusMessage *msg, E_DBus_Unmarshal_Func unmarshal_func, E_DBus_Callback_Func cb_func, E_DBus_Free_Func free_func, int timeout, void *data)
+{
+  E_DBus_Callback *cb;
+
+  EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+  cb = e_dbus_callback_new(cb_func, unmarshal_func, free_func, data);
+  return e_dbus_message_send(conn, msg, cb_method_call, timeout, cb);
+}
diff --git a/src/lib/dbus/e_dbus_methods.c b/src/lib/dbus/e_dbus_methods.c
new file mode 100644 (file)
index 0000000..cb1003d
--- /dev/null
@@ -0,0 +1,175 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "e_dbus_private.h"
+
+static inline DBusMessage *
+_dbus_message_method_call(const char *method_name)
+{
+   DBusMessage *msg;
+
+   msg = dbus_message_new_method_call
+     (E_DBUS_FDO_BUS, E_DBUS_FDO_PATH, E_DBUS_FDO_INTERFACE,
+      method_name);
+   if (!msg)
+     ERR("E-dbus Error: failed to create message for method call: %s",
+          method_name);
+   return msg;
+}
+
+static inline DBusPendingCall *
+_dbus_call__void(E_DBus_Connection *conn, const const char *method_name, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+  DBusMessage *msg;
+  DBusPendingCall *ret;
+
+  if (!conn)
+    {
+      ERR("E.dbus Error: no connection for call of %s", method_name);
+      return NULL;
+    }
+  
+  msg = _dbus_message_method_call(method_name);
+  if (!msg)
+    return NULL;
+  ret = e_dbus_message_send(conn, msg, cb_return, -1, (void *)data);
+  dbus_message_unref(msg);
+
+  if (!ret)
+    ERR("E-dbus Error: failed to call %s()", method_name);
+
+  return ret;
+}
+
+static inline DBusPendingCall *
+_dbus_call__str(E_DBus_Connection *conn, const const char *method_name, const char *str, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+  DBusMessage *msg;
+  DBusPendingCall *ret;
+
+  if (!conn)
+    {
+      ERR("E-dbus Error: no connection for call of %s", method_name);
+       return NULL;
+    }
+
+  msg = _dbus_message_method_call(method_name);
+  if (!msg)
+    return NULL;
+  dbus_message_append_args(msg, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
+  ret = e_dbus_message_send(conn, msg, cb_return, -1, (void *)data);
+  dbus_message_unref(msg);
+
+  if (!ret)
+    ERR("E-dbus Error: failed to call %s(\"%s\")", method_name, str);
+  
+  return ret;
+}
+
+EAPI DBusPendingCall *
+e_dbus_introspect(E_DBus_Connection *conn, const char *bus, const char *object_path, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+   DBusPendingCall *ret;
+   DBusMessage *msg;
+
+  if (!conn)
+    {
+       ERR("E-dbus Error: no connection for use with introspection");
+       return NULL;
+    }
+
+   msg = dbus_message_new_method_call
+     (bus, object_path, "org.freedesktop.DBus.Introspectable", "Introspect");
+   if (!msg)
+     return NULL;
+   ret = e_dbus_message_send(conn, msg, cb_return, -1, (void *)data);
+   dbus_message_unref(msg);
+   return ret;
+}
+
+EAPI DBusPendingCall *
+e_dbus_request_name(E_DBus_Connection *conn, const char *name, unsigned int flags, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+   DBusPendingCall *ret;
+   DBusMessage *msg;
+   dbus_uint32_t u_flags;
+
+  if (!conn)
+    {
+       ERR("E-dbus Error: no connection for call of RequestName");
+       return NULL;
+    }
+
+   u_flags = flags;
+
+   msg = _dbus_message_method_call("RequestName");
+   if (!msg)
+     return NULL;
+   dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_UINT32, &u_flags, DBUS_TYPE_INVALID);
+   ret = e_dbus_message_send(conn, msg, cb_return, -1, (void *)data);
+   dbus_message_unref(msg);
+   return ret;
+}
+
+EAPI DBusPendingCall *
+e_dbus_release_name(E_DBus_Connection *conn, const char *name, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+   return _dbus_call__str(conn, "ReleaseName", name, cb_return, data);
+}
+
+
+EAPI DBusPendingCall *
+e_dbus_get_name_owner(E_DBus_Connection *conn, const char *name, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+   return _dbus_call__str(conn, "GetNameOwner", name, cb_return, data);
+}
+
+EAPI DBusPendingCall *
+e_dbus_list_names(E_DBus_Connection *conn, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+   return _dbus_call__void(conn, "ListNames", cb_return, data);
+}
+
+
+EAPI DBusPendingCall *
+e_dbus_list_activatable_names(E_DBus_Connection *conn, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+   return _dbus_call__void(conn, "ListActivatableNames", cb_return, data);
+}
+
+EAPI DBusPendingCall *
+e_dbus_name_has_owner(E_DBus_Connection *conn, const char *name, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+   return _dbus_call__str(conn, "NameHasOwner", name, cb_return, data);
+}
+
+
+EAPI DBusPendingCall *
+e_dbus_start_service_by_name(E_DBus_Connection *conn, const char *name, unsigned int flags, E_DBus_Method_Return_Cb cb_return, const void *data)
+{
+   const char method_name[] = "StartServiceByName";
+   DBusMessage *msg;
+   DBusPendingCall *ret;
+
+   if (!conn)
+     {
+       ERR("ERROR: no connection for call of %s", method_name);
+       return NULL;
+     }
+
+   msg = _dbus_message_method_call(method_name);
+   if (!msg)
+     return NULL;
+   dbus_message_append_args(msg,
+                           DBUS_TYPE_STRING, &name,
+                           DBUS_TYPE_UINT32, &flags,
+                           DBUS_TYPE_INVALID);
+   ret = e_dbus_message_send(conn, msg, cb_return, -1, (void *)data);
+   dbus_message_unref(msg);
+
+   if (!ret)
+     ERR("E-dbus Error: failed to call %s(\"%s\")", method_name, name);
+
+   return ret;
+}
diff --git a/src/lib/dbus/e_dbus_object.c b/src/lib/dbus/e_dbus_object.c
new file mode 100644 (file)
index 0000000..d649c3b
--- /dev/null
@@ -0,0 +1,713 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "e_dbus_private.h"
+
+static E_DBus_Interface *introspectable_interface = NULL;
+static E_DBus_Interface *properties_interface = NULL;
+
+typedef struct E_DBus_Method E_DBus_Method;
+typedef struct E_DBus_Signal E_DBus_Signal;
+
+Eina_Strbuf * e_dbus_object_introspect(E_DBus_Object *obj);
+
+static void e_dbus_object_unregister(DBusConnection *conn, void *user_data);
+static DBusHandlerResult e_dbus_object_handler(DBusConnection *conn, DBusMessage *message, void *user_data);
+
+static void e_dbus_interface_free(E_DBus_Interface *iface);
+
+static E_DBus_Method *e_dbus_method_new(const char *member, const char *signature, const char *reply_signature, E_DBus_Method_Cb func);
+static void e_dbus_object_method_free(E_DBus_Method *m);
+
+static E_DBus_Signal *e_dbus_signal_new(const char *name, const char *signature);
+static void e_dbus_object_signal_free(E_DBus_Signal *s);
+
+static void _introspect_indent_append(Eina_Strbuf *buf, int level);
+static void _introspect_interface_append(Eina_Strbuf *buf, E_DBus_Interface *iface, int level);
+static void _introspect_method_append(Eina_Strbuf *buf, E_DBus_Method *method, int level);
+static void _introspect_signal_append(Eina_Strbuf *buf, E_DBus_Signal *signal, int level);
+static void _introspect_arg_append(Eina_Strbuf *buf, const char *type, const char *direction, int level);
+
+
+//static Eina_List *standard_methods = NULL;
+
+
+static DBusObjectPathVTable vtable = {
+  e_dbus_object_unregister,
+  e_dbus_object_handler,
+  NULL,
+  NULL,
+  NULL,
+  NULL
+};
+
+struct E_DBus_Object
+{
+  E_DBus_Connection *conn;
+  char *path;
+  Eina_List *interfaces;
+  char *introspection_data;
+  int introspection_dirty;
+
+  E_DBus_Object_Property_Get_Cb cb_property_get;
+  E_DBus_Object_Property_Set_Cb cb_property_set;
+
+  void *data;
+};
+
+struct E_DBus_Interface
+{
+  char *name;
+  Eina_List *methods;
+  Eina_List *signals;
+  int refcount;
+};
+
+struct E_DBus_Method
+{
+  char *member;
+  char *signature;
+  char *reply_signature;
+  E_DBus_Method_Cb func;
+};
+
+struct E_DBus_Signal
+{
+  char *name;
+  char *signature;
+};
+
+static DBusMessage *
+cb_introspect(E_DBus_Object *obj, DBusMessage *msg)
+{
+  DBusMessage *ret;
+  Eina_Strbuf *buf;
+
+  if (obj->introspection_dirty || !obj->introspection_data)
+  {
+    buf = e_dbus_object_introspect(obj);
+    if (!buf)
+    {
+      ret = dbus_message_new_error(msg, "org.enlightenment.NotIntrospectable", "This object does not provide introspection data");
+      return ret;
+    }
+
+    if (obj->introspection_data) free(obj->introspection_data);
+    obj->introspection_data = strdup(eina_strbuf_string_get(buf));
+    eina_strbuf_free(buf);
+  }
+  //printf("XML: \n\n%s\n\n", obj->introspection_data);
+  ret = dbus_message_new_method_return(msg);
+  dbus_message_append_args(ret, DBUS_TYPE_STRING, &(obj->introspection_data), DBUS_TYPE_INVALID);
+
+  return ret;
+}
+
+static DBusMessage *
+cb_properties_get(E_DBus_Object *obj, DBusMessage *msg)
+{
+  DBusMessage *reply;
+  DBusMessageIter iter, sub;
+  DBusError err;
+  int type;
+  void *value;
+  char *property, *interface;
+
+  dbus_error_init(&err);
+  dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING,
+                        &property, DBUS_TYPE_INVALID);
+
+  if (dbus_error_is_set(&err))
+  {
+    return dbus_message_new_error(msg, err.name, err.message);
+  }
+
+  /*
+   * FIXME: there's no way to pass interface the interface here - this shall be
+   * fixed by another callback function, since fixing it here would break the
+   * API.
+   */
+  obj->cb_property_get(obj, property, &type, &value);
+  if (type == DBUS_TYPE_INVALID)
+  {
+    return dbus_message_new_error_printf(msg, "org.enlightenment.DBus.InvalidProperty", "The property '%s' does not exist on this object.", property);
+  }
+
+  if (dbus_type_is_basic(type))
+  {
+    reply = dbus_message_new_method_return(msg);
+    dbus_message_iter_init_append(reply, &iter);
+    if (dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, e_dbus_basic_type_as_string(type), &sub))
+    {
+      dbus_message_iter_append_basic(&sub, type, &value);
+      dbus_message_iter_close_container(&iter, &sub);
+    }
+    else
+    {
+      ERR("dbus_message_iter_open_container() failed");
+    }
+    return reply;
+  }
+  else
+  {
+    return dbus_message_new_error(msg, "org.enlightenment.DBus.UnsupportedType", "E_DBus currently only supports properties of a basic type.");
+  }
+}
+
+static DBusMessage *
+cb_properties_set(E_DBus_Object *obj, DBusMessage *msg)
+{
+  DBusMessageIter iter, sub;
+  int type;
+  void *value;
+  char *property, *interface;
+
+  dbus_message_iter_init(msg, &iter);
+  dbus_message_iter_get_basic(&iter, &interface);
+  dbus_message_iter_next(&iter);
+  dbus_message_iter_get_basic(&iter, &property);
+  dbus_message_iter_next(&iter);
+  dbus_message_iter_recurse(&iter, &sub);
+  type = dbus_message_iter_get_arg_type(&sub);
+  if (dbus_type_is_basic(type))
+  {
+    dbus_message_iter_get_basic(&sub, &value);
+
+    /*
+     * FIXME: there's no way to pass interface the interface here - this shall
+     * be fixed by another callback function, since fixing it here would break
+     * the API.
+     */
+    if (obj->cb_property_set(obj, property, type, value))
+    {
+      return dbus_message_new_method_return(msg);
+    }
+    else
+    {
+      return dbus_message_new_error_printf(msg, "org.enlightenment.DBus.InvalidProperty", "The property '%s' does not exist on this object.", property);
+    }
+  }
+  else
+  {
+    return dbus_message_new_error(msg, "org.enlightenment.DBus.UnsupportedType", "E_DBus currently only supports properties of a basic type.");
+  }
+
+}
+
+int
+e_dbus_object_init(void)
+{
+  introspectable_interface = e_dbus_interface_new("org.freedesktop.DBus.Introspectable");
+  properties_interface = e_dbus_interface_new(E_DBUS_FDO_INTERFACE_PROPERTIES);
+  if (!introspectable_interface || !properties_interface)
+  {
+    if (introspectable_interface) e_dbus_interface_unref(introspectable_interface);
+    introspectable_interface = NULL;
+    if (properties_interface) e_dbus_interface_unref(properties_interface);
+    properties_interface = NULL;
+    return 0;
+  }
+
+  e_dbus_interface_method_add(introspectable_interface, "Introspect", "", "s", cb_introspect);
+  e_dbus_interface_method_add(properties_interface, "Get", "ss", "v", cb_properties_get);
+  e_dbus_interface_method_add(properties_interface, "Set", "ssv", "", cb_properties_set);
+  return 1;
+}
+
+void
+e_dbus_object_shutdown(void)
+{
+  e_dbus_interface_unref(introspectable_interface);
+  introspectable_interface = NULL;
+
+  e_dbus_interface_unref(properties_interface);
+  properties_interface = NULL;
+}
+
+EAPI E_DBus_Object *
+e_dbus_object_add(E_DBus_Connection *conn, const char *object_path, void *data)
+{
+  E_DBus_Object *obj;
+
+  EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+  EINA_SAFETY_ON_NULL_RETURN_VAL(object_path, NULL);
+
+  obj = calloc(1, sizeof(E_DBus_Object));
+  if (!obj) return NULL;
+
+  if (!dbus_connection_register_object_path(conn->conn, object_path, &vtable, obj))
+  {
+    free(obj);
+    return NULL;
+  }
+
+  obj->conn = conn;
+  e_dbus_connection_ref(conn);
+  obj->path = strdup(object_path);
+  obj->data = data;
+  obj->interfaces = NULL;
+
+  e_dbus_object_interface_attach(obj, introspectable_interface);
+
+  return obj;
+}
+
+EAPI void
+e_dbus_object_free(E_DBus_Object *obj)
+{
+  E_DBus_Interface *iface;
+
+  if (!obj) return;
+
+  DBG("e_dbus_object_free (%s)", obj->path);
+  dbus_connection_unregister_object_path(obj->conn->conn, obj->path);
+  e_dbus_connection_close(obj->conn);
+
+  if (obj->path) free(obj->path);
+  EINA_LIST_FREE(obj->interfaces, iface)
+    e_dbus_interface_unref(iface);
+
+  if (obj->introspection_data) free(obj->introspection_data);
+
+  free(obj);
+}
+
+EAPI void *
+e_dbus_object_data_get(E_DBus_Object *obj)
+{
+  EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
+  return obj->data;
+}
+
+EAPI E_DBus_Connection *
+e_dbus_object_conn_get(E_DBus_Object *obj)
+{
+  EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
+  return obj->conn;
+}
+
+EAPI const char *
+e_dbus_object_path_get(E_DBus_Object *obj)
+{
+  EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
+  return obj->path;
+}
+
+EAPI const Eina_List *
+e_dbus_object_interfaces_get(E_DBus_Object *obj)
+{
+  EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
+  return obj->interfaces;
+}
+
+EAPI void
+e_dbus_object_property_get_cb_set(E_DBus_Object *obj, E_DBus_Object_Property_Get_Cb func)
+{
+  EINA_SAFETY_ON_NULL_RETURN(obj);
+  if (obj->cb_property_get == NULL && obj->cb_property_set == NULL)
+    e_dbus_object_interface_attach(obj, properties_interface);
+  obj->cb_property_get = func;
+}
+
+EAPI void
+e_dbus_object_property_set_cb_set(E_DBus_Object *obj, E_DBus_Object_Property_Set_Cb func)
+{
+  EINA_SAFETY_ON_NULL_RETURN(obj);
+  if (obj->cb_property_get == NULL && obj->cb_property_set == NULL)
+    e_dbus_object_interface_attach(obj, properties_interface);
+  obj->cb_property_set = func;
+}
+
+EAPI void
+e_dbus_object_interface_attach(E_DBus_Object *obj, E_DBus_Interface *iface)
+{
+  E_DBus_Interface *iface_added;
+  Eina_List *l;
+  EINA_SAFETY_ON_NULL_RETURN(obj);
+  EINA_SAFETY_ON_NULL_RETURN(iface);
+
+  EINA_LIST_FOREACH(obj->interfaces, l, iface_added)
+    {
+       if (strcmp(iface->name, iface_added->name) == 0)
+         {
+            ERR("This object(%s) already have this interface name(%s) attached",
+                obj->path, iface->name);
+            return;
+         }
+    }
+
+  e_dbus_interface_ref(iface);
+  obj->interfaces = eina_list_append(obj->interfaces, iface);
+  obj->introspection_dirty = 1;
+  DBG("e_dbus_object_interface_attach (%s, %s) ", obj->path, iface->name);
+}
+
+EAPI void
+e_dbus_object_interface_detach(E_DBus_Object *obj, E_DBus_Interface *iface)
+{
+  E_DBus_Interface *found;
+
+  EINA_SAFETY_ON_NULL_RETURN(obj);
+  EINA_SAFETY_ON_NULL_RETURN(iface);
+  DBG("e_dbus_object_interface_detach (%s, %s) ", obj->path, iface->name);
+  found = eina_list_data_find(obj->interfaces, iface);
+  if (!found) return;
+
+  obj->interfaces = eina_list_remove(obj->interfaces, iface);
+  obj->introspection_dirty = 1;
+  e_dbus_interface_unref(iface);
+}
+
+EAPI void
+e_dbus_interface_ref(E_DBus_Interface *iface)
+{
+  EINA_SAFETY_ON_NULL_RETURN(iface);
+  iface->refcount++;
+  DBG("e_dbus_interface_ref (%s) = %d", iface->name, iface->refcount);
+}
+
+EAPI void
+e_dbus_interface_unref(E_DBus_Interface *iface)
+{
+  EINA_SAFETY_ON_NULL_RETURN(iface);
+  DBG("e_dbus_interface_unref (%s) = %d", iface->name, iface->refcount - 1);
+  if (--(iface->refcount) == 0)
+    e_dbus_interface_free(iface);
+}
+
+static void
+e_dbus_interface_free(E_DBus_Interface *iface)
+{
+  E_DBus_Method *m;
+  E_DBus_Signal *s;
+
+  if (iface->name) free(iface->name);
+  EINA_LIST_FREE(iface->methods, m)
+    e_dbus_object_method_free(m);
+  EINA_LIST_FREE(iface->signals, s)
+    e_dbus_object_signal_free(s);
+  free(iface);
+}
+
+
+EAPI int
+e_dbus_interface_method_add(E_DBus_Interface *iface, const char *member, const char *signature, const char *reply_signature, E_DBus_Method_Cb func)
+{
+  E_DBus_Method *m;
+
+  EINA_SAFETY_ON_NULL_RETURN_VAL(iface, 0);
+  m = e_dbus_method_new(member, signature, reply_signature, func);
+  DBG("E-dbus: Add method %s: %p", member, m);
+  if (!m) return 0;
+
+  iface->methods = eina_list_append(iface->methods, m);
+  return 1;
+}
+
+EAPI int
+e_dbus_interface_signal_add(E_DBus_Interface *iface, const char *name, const char *signature)
+{
+  E_DBus_Signal *s;
+
+  EINA_SAFETY_ON_NULL_RETURN_VAL(iface, 0);
+  s = e_dbus_signal_new(name, signature);
+  DBG("E-dbus: Add signal %s: %p", name, s);
+  if (!s) return 0;
+
+  iface->signals = eina_list_append(iface->signals, s);
+  return 1;
+}
+
+EAPI E_DBus_Interface *
+e_dbus_interface_new(const char *interface)
+{
+  E_DBus_Interface *iface;
+
+  if (!interface) return NULL;
+
+  iface = calloc(1, sizeof(E_DBus_Interface));
+  if (!iface) return NULL;
+
+  iface->refcount = 1;
+  iface->name = strdup(interface);
+  iface->methods = NULL;
+  iface->signals = NULL;
+
+  return iface;
+}
+
+static E_DBus_Method *
+e_dbus_method_new(const char *member, const char *signature, const char *reply_signature, E_DBus_Method_Cb func)
+{
+  E_DBus_Method *m;
+
+  if (!member || !func) return NULL;
+
+  if (signature && !dbus_signature_validate(signature, NULL)) return NULL;
+  if (reply_signature && !dbus_signature_validate(reply_signature, NULL)) return NULL;
+  m = calloc(1, sizeof(E_DBus_Method));
+  if (!m) return NULL;
+
+  m->member = strdup(member);
+  if (signature)
+    m->signature = strdup(signature);
+  if (reply_signature)
+    m->reply_signature = strdup(reply_signature);
+  m->func = func;
+
+  return m;
+}
+
+static void
+e_dbus_object_method_free(E_DBus_Method *m)
+{
+  if (!m) return;
+  if (m->member) free(m->member);
+  if (m->signature) free(m->signature);
+  if (m->reply_signature) free(m->reply_signature);
+
+  free(m);
+}
+
+static E_DBus_Signal *
+e_dbus_signal_new(const char *name, const char *signature)
+{
+  E_DBus_Signal *s;
+
+  if (!name) return NULL;
+
+  if (signature && !dbus_signature_validate(signature, NULL)) return NULL;
+  s = calloc(1, sizeof(E_DBus_Signal));
+  if (!s) return NULL;
+
+  s->name = strdup(name);
+  if (signature)
+    s->signature = strdup(signature);
+
+  return s;
+}
+
+static void
+e_dbus_object_signal_free(E_DBus_Signal *s)
+{
+  if (!s) return;
+  if (s->name) free(s->name);
+  if (s->signature) free(s->signature);
+  free(s);
+}
+
+static E_DBus_Method *
+e_dbus_object_method_find(E_DBus_Object *obj, const char *interface, const char *member)
+{
+  E_DBus_Method *m;
+  E_DBus_Interface *iface;
+  Eina_List *l, *ll;
+
+  if (!obj || !member) return NULL;
+
+  EINA_LIST_FOREACH(obj->interfaces, l, iface)
+  {
+    if (strcmp(interface, iface->name)) continue;
+    EINA_LIST_FOREACH(iface->methods, ll, m)
+    {
+      if (!strcmp(member, m->member))
+        return m;
+    }
+  }
+  return NULL;
+}
+
+static DBusHandlerResult
+e_dbus_object_handler(DBusConnection *conn, DBusMessage *message, void *user_data) 
+{
+  E_DBus_Object *obj;
+  E_DBus_Method *m;
+  DBusMessage *reply;
+  dbus_uint32_t serial;
+
+  obj = user_data;
+  if (!obj)
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+  m = e_dbus_object_method_find(obj, dbus_message_get_interface(message), dbus_message_get_member(message));
+
+  /* XXX should this send an 'invalid method' error instead? */
+  if (!m) 
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+  if (m->signature && !dbus_message_has_signature(message, m->signature))
+    reply = dbus_message_new_error_printf(message, "org.enlightenment.InvalidSignature", "Expected signature: %s", m->signature);
+  else
+    reply = m->func(obj, message);
+
+  /* user can choose reply later */
+  if (!reply)
+    return DBUS_HANDLER_RESULT_HANDLED;
+
+  dbus_connection_send(conn, reply, &serial);
+  dbus_message_unref(reply);
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void
+e_dbus_object_unregister(DBusConnection *conn __UNUSED__, void *user_data __UNUSED__)
+{
+  /* free up the object struct? */
+}
+
+Eina_Strbuf *
+e_dbus_object_introspect(E_DBus_Object *obj)
+{
+  Eina_Strbuf *buf;
+  int level = 0;
+  E_DBus_Interface *iface;
+  Eina_List *l;
+
+  buf = eina_strbuf_new();
+
+  /* Doctype */
+  eina_strbuf_append(buf, "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n");
+
+  eina_strbuf_append(buf, "<node name=\"");
+  eina_strbuf_append(buf, obj->path);
+  eina_strbuf_append(buf, "\">\n");
+  level++;
+
+  EINA_LIST_FOREACH(obj->interfaces, l, iface)
+    _introspect_interface_append(buf, iface, level);
+
+  eina_strbuf_append(buf, "</node>\n");
+  return buf;
+}
+
+static void
+_introspect_indent_append(Eina_Strbuf *buf, int level)
+{
+  /* XXX optimize this? */
+  int i = level * 2;
+  while (i-- > 0)
+    eina_strbuf_append_char(buf, ' ');
+}
+static void
+_introspect_interface_append(Eina_Strbuf *buf, E_DBus_Interface *iface, int level)
+{
+  E_DBus_Method *m;
+  E_DBus_Signal *s;
+  Eina_List *l;
+
+  _introspect_indent_append(buf, level);
+  eina_strbuf_append(buf, "<interface name=\"");
+  eina_strbuf_append(buf, iface->name);
+  eina_strbuf_append(buf, "\">\n");
+  level++;
+
+  DBG("introspect iface: %s", iface->name);
+  EINA_LIST_FOREACH(iface->methods, l, m)
+    _introspect_method_append(buf, m, level);
+  EINA_LIST_FOREACH(iface->signals, l, s)
+    _introspect_signal_append(buf, s, level);
+
+  level--;
+  _introspect_indent_append(buf, level);
+  eina_strbuf_append(buf, "</interface>\n");
+}
+static void
+_introspect_method_append(Eina_Strbuf *buf, E_DBus_Method *method, int level)
+{
+  DBusSignatureIter iter;
+  char *type;
+
+  _introspect_indent_append(buf, level);
+  DBG("introspect method: %s\n", method->member);
+  eina_strbuf_append(buf, "<method name=\"");
+  eina_strbuf_append(buf, method->member);
+  eina_strbuf_append(buf, "\">\n");
+  level++;
+
+  /* append args */
+  if (method->signature && 
+      method->signature[0] &&
+      dbus_signature_validate(method->signature, NULL))
+  {
+    dbus_signature_iter_init(&iter, method->signature);
+    while ((type = dbus_signature_iter_get_signature(&iter)))
+    {
+      _introspect_arg_append(buf, type, "in", level);
+
+      dbus_free(type);
+      if (!dbus_signature_iter_next(&iter)) break;
+    }
+  }
+
+  /* append reply args */
+  if (method->reply_signature &&
+      method->reply_signature[0] &&
+      dbus_signature_validate(method->reply_signature, NULL))
+  {
+    dbus_signature_iter_init(&iter, method->reply_signature);
+    while ((type = dbus_signature_iter_get_signature(&iter)))
+    {
+      _introspect_arg_append(buf, type, "out", level);
+
+      dbus_free(type);
+      if (!dbus_signature_iter_next(&iter)) break;
+    }
+  }
+
+  level--;
+  _introspect_indent_append(buf, level);
+  eina_strbuf_append(buf, "</method>\n");
+}
+
+static void
+_introspect_signal_append(Eina_Strbuf *buf, E_DBus_Signal *s, int level)
+{
+  DBusSignatureIter iter;
+  char *type;
+
+  _introspect_indent_append(buf, level);
+  DBG("introspect signal: %s", s->name);
+  eina_strbuf_append(buf, "<signal name=\"");
+  eina_strbuf_append(buf, s->name);
+  eina_strbuf_append(buf, "\">\n");
+  level++;
+
+  /* append args */
+  if (s->signature &&
+      s->signature[0] &&
+      dbus_signature_validate(s->signature, NULL))
+  {
+    dbus_signature_iter_init(&iter, s->signature);
+    while ((type = dbus_signature_iter_get_signature(&iter)))
+    {
+      _introspect_arg_append(buf, type, NULL, level);
+
+      dbus_free(type);
+      if (!dbus_signature_iter_next(&iter)) break;
+    }
+  }
+
+  level--;
+  _introspect_indent_append(buf, level);
+  eina_strbuf_append(buf, "</signal>\n");
+}
+
+static void
+_introspect_arg_append(Eina_Strbuf *buf, const char *type, const char *direction, int level)
+{
+  _introspect_indent_append(buf, level);
+  eina_strbuf_append(buf, "<arg type=\"");
+  eina_strbuf_append(buf, type);
+  if (direction)
+  {
+    eina_strbuf_append(buf, "\" direction=\"");
+    eina_strbuf_append(buf, direction);
+  }
+  eina_strbuf_append(buf, "\"/>\n");
+}
+
diff --git a/src/lib/dbus/e_dbus_private.h b/src/lib/dbus/e_dbus_private.h
new file mode 100644 (file)
index 0000000..93fce49
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef E_DBUS_PRIVATE_H
+#define E_DBUS_PRIVATE_H
+
+#include <Ecore.h>
+
+#include "E_DBus.h"
+
+#ifndef E_DBUS_COLOR_DEFAULT
+#define E_DBUS_COLOR_DEFAULT EINA_COLOR_CYAN
+#endif
+EAPI extern int _e_dbus_log_dom;
+#define DBG(...)   EINA_LOG_DOM_DBG(_e_dbus_log_dom, __VA_ARGS__)
+#define INFO(...)    EINA_LOG_DOM_INFO(_e_dbus_log_dom, __VA_ARGS__)
+#define WARN(...) EINA_LOG_DOM_WARN(_e_dbus_log_dom, __VA_ARGS__)
+#define ERR(...)   EINA_LOG_DOM_ERR(_e_dbus_log_dom, __VA_ARGS__)
+
+
+struct E_DBus_Connection
+{
+  DBusBusType shared_type;
+  DBusConnection *conn;
+  char *conn_name;
+
+  Eina_List *fd_handlers;
+  Eina_List *timeouts;
+  Eina_List *signal_handlers;
+  void (*signal_dispatcher)(E_DBus_Connection *conn, DBusMessage *msg);
+
+  Ecore_Idler *idler;
+
+  int refcount;
+};
+
+struct E_DBus_Callback
+{
+  E_DBus_Callback_Func cb_func;
+  E_DBus_Unmarshal_Func unmarshal_func;
+  E_DBus_Free_Func free_func;
+  void *user_data;
+};
+
+int  e_dbus_object_init(void);
+void e_dbus_object_shutdown(void);
+
+extern int e_dbus_idler_active;
+void e_dbus_signal_handlers_clean(E_DBus_Connection *conn);
+void e_dbus_signal_handlers_free_all(E_DBus_Connection *conn);
+
+
+const char *e_dbus_basic_type_as_string(int type);
+
+  
+#endif
diff --git a/src/lib/dbus/e_dbus_signal.c b/src/lib/dbus/e_dbus_signal.c
new file mode 100644 (file)
index 0000000..0688757
--- /dev/null
@@ -0,0 +1,271 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "e_dbus_private.h"
+
+#define SENDER_KEY "sender"
+#define PATH_KEY "path"
+#define INTERFACE_KEY "interface"
+#define MEMBER_KEY "member"
+#define NAME_OWNER_MATCH "type='signal',sender='org.freedesktop.DBus',\
+         path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',\
+         member='NameOwnerChanged',arg0='%s'"
+#define MEMBER_NAME_OWNER_CHANGED "NameOwnerChanged"
+
+struct E_DBus_Signal_Handler
+{
+   char *sender;
+   char *path;
+   char *interface;
+   char *member;
+   char *owner;
+   char *match;
+   char *match_name_owner_change;
+   
+   E_DBus_Signal_Cb cb_signal;
+   DBusPendingCall *get_name_owner_pending;
+   void *data;
+   unsigned char delete_me : 1;
+};
+
+static void cb_signal_dispatcher(E_DBus_Connection *conn, DBusMessage *msg);
+
+/*
+ * Free a signal handler
+ * @param sh the signal handler to free
+ */
+static void
+e_dbus_signal_handler_free(E_DBus_Signal_Handler *sh)
+{
+  free(sh->sender);
+  free(sh->interface);
+  free(sh->path);
+  free(sh->member);
+  free(sh->owner);
+  free(sh->match);
+  free(sh->match_name_owner_change);
+  free(sh);
+}
+
+struct cb_name_owner_data
+{
+   E_DBus_Connection *conn;
+   E_DBus_Signal_Handler *sh;
+};
+
+static void
+cb_name_owner(void *data, DBusMessage *msg, DBusError *err)
+{
+  const char *unique_name = NULL;
+  struct cb_name_owner_data *d = data;
+  E_DBus_Signal_Handler *sh;
+  DBusError new_err;
+
+  sh = d->sh;
+  sh->get_name_owner_pending = NULL;
+  free(d);
+
+  if (dbus_error_is_set(err)) return;
+
+  dbus_error_init(&new_err);
+  dbus_message_get_args(msg, &new_err, DBUS_TYPE_STRING,
+                        &unique_name, DBUS_TYPE_INVALID);
+
+  if (dbus_error_is_set(&new_err)) return;
+
+  if (unique_name != NULL && unique_name[0]) sh->owner = strdup(unique_name);
+}
+
+static void
+_match_append(Eina_Strbuf *match, const char *key, const char *value)
+{
+   if (value == NULL || !value[0]) return;
+
+   if ((eina_strbuf_length_get(match) + 4 + strlen(key) + strlen(value))
+       >= DBUS_MAXIMUM_MATCH_RULE_LENGTH)
+     {
+        ERR("cannot add match %s='%s' to %s: too long!", key, value,
+            eina_strbuf_string_get(match));
+        return;
+     }
+
+   eina_strbuf_append_printf(match, ",%s='%s'", key, value);
+}
+
+EAPI E_DBus_Signal_Handler *
+e_dbus_signal_handler_add(E_DBus_Connection *conn, const char *sender, const char *path, const char *interface, const char *member, E_DBus_Signal_Cb cb_signal, void *data)
+{
+  E_DBus_Signal_Handler *sh;
+  Eina_Strbuf *match;
+  DBusError err;
+
+  EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+  sh = calloc(1, sizeof(E_DBus_Signal_Handler));
+  if (!sh)
+    {
+       ERR("could not allocate signal handler.");
+       return NULL;
+    }
+
+  match = eina_strbuf_new();
+  eina_strbuf_append(match, "type='signal'");
+
+  _match_append(match, SENDER_KEY, sender);
+  _match_append(match, PATH_KEY, path);
+  _match_append(match, INTERFACE_KEY, interface);
+  _match_append(match, MEMBER_KEY, member);
+
+  if (sender) sh->sender = strdup(sender);
+  if (path) sh->path = strdup(path);
+  if (interface) sh->interface = strdup(interface);
+  if (member) sh->member = strdup(member);
+  sh->match = strdup(eina_strbuf_string_get(match));
+
+  sh->cb_signal = cb_signal;
+  sh->get_name_owner_pending = NULL;
+  sh->data = data;
+  sh->delete_me = 0;
+
+  dbus_error_init(&err);
+  dbus_bus_add_match(conn->conn, sh->match, &err);
+
+  if (!conn->signal_handlers) conn->signal_dispatcher = cb_signal_dispatcher;
+
+  /* if we have a sender, and it is not a unique name, we need to know the
+   * unique name to match since signals will have the name owner as their
+   * sender.
+   */
+  if (sender && sender[0] != ':' && strcmp(sender, E_DBUS_FDO_BUS) != 0)
+    {
+       struct cb_name_owner_data *data_cb;
+
+       // listen when the owner of the sender name change
+       eina_strbuf_reset(match);
+       eina_strbuf_append_printf(match, NAME_OWNER_MATCH, sh->sender);
+       sh->match_name_owner_change = strdup(eina_strbuf_string_get(match));
+
+       dbus_bus_add_match(conn->conn, sh->match_name_owner_change, NULL);
+       DBG("add name owner match=%s", sh->match_name_owner_change);
+
+       data_cb = malloc(sizeof(*data_cb));
+       if (!data_cb)
+        {
+           e_dbus_signal_handler_free(sh);
+           eina_strbuf_free(match);
+            ERR("could not allocate cb_name_owner_data.");
+           return NULL;
+        }
+       data_cb->conn = conn;
+       data_cb->sh = sh;
+       sh->get_name_owner_pending =
+         e_dbus_get_name_owner(conn, sender, cb_name_owner, data_cb);
+    }
+  else if (sender) sh->owner = strdup(sender);
+
+  eina_strbuf_free(match);
+  conn->signal_handlers = eina_list_append(conn->signal_handlers, sh);
+
+  return sh;
+}
+
+static int e_dbus_handler_deletions = 0;
+
+EAPI void
+e_dbus_signal_handler_del(E_DBus_Connection *conn, E_DBus_Signal_Handler *sh)
+{
+   if ((!conn) || (!sh)) return;
+
+   if (sh->get_name_owner_pending)
+     {
+        dbus_pending_call_cancel(sh->get_name_owner_pending);
+        sh->get_name_owner_pending = NULL;
+     }
+   sh->delete_me = 1;
+   if (e_dbus_idler_active)
+     {
+        e_dbus_handler_deletions = 1;
+        return;
+     }
+
+   conn->signal_handlers = eina_list_remove(conn->signal_handlers, sh);
+
+   dbus_bus_remove_match(conn->conn, sh->match, NULL);
+   if (sh->match_name_owner_change)
+     dbus_bus_remove_match(conn->conn, sh->match_name_owner_change, NULL);
+
+   e_dbus_signal_handler_free(sh);
+}
+
+static void
+cb_signal_dispatcher(E_DBus_Connection *conn, DBusMessage *msg)
+{
+  E_DBus_Signal_Handler *sh;
+  Eina_List *l;
+
+  if(dbus_message_has_sender(msg, E_DBUS_FDO_BUS) &&
+     dbus_message_has_path(msg, E_DBUS_FDO_PATH) &&
+     dbus_message_has_interface(msg, E_DBUS_FDO_INTERFACE) &&
+     dbus_message_has_member(msg, MEMBER_NAME_OWNER_CHANGED))
+    {
+       DBusError new_err;
+       char *bus, *old_owner, *new_owner;
+       dbus_error_init(&new_err);
+       dbus_message_get_args(msg, &new_err, DBUS_TYPE_STRING, &bus,
+                             DBUS_TYPE_STRING, &old_owner,
+                             DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID);
+
+       if (dbus_error_is_set(&new_err)) return;
+
+       EINA_LIST_FOREACH(conn->signal_handlers, l, sh)
+         {
+            if (!sh->delete_me && sh->sender && strcmp(sh->sender, bus) == 0)
+              {
+                 free(sh->owner);
+                 sh->owner = NULL;
+                 if (new_owner != NULL && new_owner[0])
+                    sh->owner = strdup(new_owner);
+              }
+         }
+    }
+
+  EINA_LIST_FOREACH(conn->signal_handlers, l, sh)
+  {
+    if ((!sh->cb_signal) || (sh->delete_me)) continue;
+
+    if (sh->get_name_owner_pending ||
+        (sh->owner && !dbus_message_has_sender(msg, sh->owner))) continue;
+    if (sh->path && !dbus_message_has_path(msg, sh->path)) continue;
+    if (sh->interface && !dbus_message_has_interface(msg, sh->interface)) continue;
+    if (sh->member && !dbus_message_has_member(msg, sh->member)) continue;
+
+    sh->cb_signal(sh->data, msg);
+  }
+}
+
+void
+e_dbus_signal_handlers_clean(E_DBus_Connection *conn)
+{
+  E_DBus_Signal_Handler *sh;
+  Eina_List *l, *l_next;
+
+  if (!e_dbus_handler_deletions) return;
+  e_dbus_handler_deletions = 0;
+  if (!conn->signal_handlers) return;
+  EINA_LIST_FOREACH_SAFE(conn->signal_handlers, l, l_next, sh)
+  {
+    if (sh->delete_me)
+      e_dbus_signal_handler_del(conn, sh);
+  }
+}
+
+void
+e_dbus_signal_handlers_free_all(E_DBus_Connection *conn)
+{
+   E_DBus_Signal_Handler *sh;
+   EINA_LIST_FREE(conn->signal_handlers, sh)
+     e_dbus_signal_handler_free(sh);
+}
diff --git a/src/lib/dbus/e_dbus_util.c b/src/lib/dbus/e_dbus_util.c
new file mode 100644 (file)
index 0000000..9fda872
--- /dev/null
@@ -0,0 +1,85 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "e_dbus_private.h"
+
+EAPI E_DBus_Callback *
+e_dbus_callback_new(E_DBus_Callback_Func cb_func, E_DBus_Unmarshal_Func unmarshal_func, E_DBus_Free_Func free_func, void *user_data)
+{
+  E_DBus_Callback *cb;
+
+  if (!cb_func) return NULL;
+
+  cb = calloc(1, sizeof(E_DBus_Callback));
+  if (!cb) return NULL;
+  cb->cb_func = cb_func;
+  cb->unmarshal_func = unmarshal_func;
+  cb->free_func = free_func;
+  cb->user_data = user_data;
+  return cb;
+}
+
+EAPI void
+e_dbus_callback_free(E_DBus_Callback *callback)
+{
+  free(callback);
+}
+
+EAPI void
+e_dbus_callback_call(E_DBus_Callback *cb, void *data, DBusError *error)
+{
+  if (cb && cb->cb_func)
+    cb->cb_func(cb->user_data, data, error);
+}
+
+EAPI void *
+e_dbus_callback_unmarshal(E_DBus_Callback *cb, DBusMessage *msg, DBusError *err)
+{
+  if (cb && cb->unmarshal_func)
+    return cb->unmarshal_func(msg, err);
+  return NULL;
+}
+
+EAPI void
+e_dbus_callback_return_free(E_DBus_Callback *cb, void *data)
+{
+  if (cb && cb->free_func)
+    cb->free_func(data);
+}
+
+const char *
+e_dbus_basic_type_as_string(int type)
+{
+  switch (type)
+  {
+    case DBUS_TYPE_BYTE:
+      return DBUS_TYPE_BYTE_AS_STRING;
+    case DBUS_TYPE_BOOLEAN:
+      return DBUS_TYPE_BOOLEAN_AS_STRING;
+    case DBUS_TYPE_INT16:
+      return DBUS_TYPE_INT16_AS_STRING;
+    case DBUS_TYPE_UINT16:
+      return DBUS_TYPE_UINT16_AS_STRING;
+    case DBUS_TYPE_INT32:
+      return DBUS_TYPE_INT32_AS_STRING;
+    case DBUS_TYPE_UINT32:
+      return DBUS_TYPE_UINT32_AS_STRING;
+    case DBUS_TYPE_INT64:
+      return DBUS_TYPE_INT64_AS_STRING;
+    case DBUS_TYPE_UINT64:
+      return DBUS_TYPE_UINT64_AS_STRING;
+    case DBUS_TYPE_DOUBLE:
+      return DBUS_TYPE_DOUBLE_AS_STRING;
+    case DBUS_TYPE_STRING:
+      return DBUS_TYPE_STRING_AS_STRING;
+    case DBUS_TYPE_OBJECT_PATH:
+      return DBUS_TYPE_OBJECT_PATH_AS_STRING;
+    case DBUS_TYPE_SIGNATURE:
+      return DBUS_TYPE_SIGNATURE_AS_STRING;
+    default:
+      return NULL;
+  }
+}
diff --git a/src/lib/hal/E_Hal.h b/src/lib/hal/E_Hal.h
new file mode 100644 (file)
index 0000000..ab86ebe
--- /dev/null
@@ -0,0 +1,128 @@
+#ifndef E_HAL_H
+#define E_HAL_H
+
+#include <Eina.h>
+#include <E_DBus.h>
+
+/**
+ * @defgroup EHal_Group EHal
+ *
+ * @{
+ */
+
+#define E_HAL_SENDER "org.freedesktop.Hal"
+#define E_HAL_MANAGER_PATH "/org/freedesktop/Hal/Manager"
+#define E_HAL_MANAGER_INTERFACE "org.freedesktop.Hal.Manager"
+#define E_HAL_DEVICE_INTERFACE "org.freedesktop.Hal.Device"
+#define E_HAL_DEVICE_VOLUME_INTERFACE "org.freedesktop.Hal.Device.Volume"
+
+/* message return types */
+
+typedef struct E_Hal_Property E_Hal_Property;
+typedef struct E_Hal_Properties E_Hal_Properties;
+
+struct E_Hal_String_List_Return
+{
+  Eina_List *strings; /* list of const char * */
+};
+
+struct E_Hal_Bool_Return
+{
+  Eina_Bool boolean;
+};
+
+struct E_Hal_UDI_Return
+{
+  const char *udi;
+};
+
+struct E_Hal_Capability
+{
+  const char *udi;
+  const char *capability;
+};
+
+typedef enum
+{
+  E_HAL_PROPERTY_TYPE_STRING,
+  E_HAL_PROPERTY_TYPE_INT,
+  E_HAL_PROPERTY_TYPE_UINT64,
+  E_HAL_PROPERTY_TYPE_BOOL,
+  E_HAL_PROPERTY_TYPE_DOUBLE,
+  E_HAL_PROPERTY_TYPE_STRLIST
+} E_Hal_Property_Type;
+
+struct E_Hal_Property
+{
+  E_Hal_Property_Type type;
+  union 
+  {
+    const char *s;
+    int i;
+    dbus_bool_t b;
+    double d;
+    dbus_uint64_t u64;
+    Eina_List *strlist;
+  } val;
+};
+
+struct E_Hal_Properties
+{
+  Eina_Hash *properties;
+};
+
+typedef struct E_Hal_Properties E_Hal_Device_Get_All_Properties_Return;
+typedef struct E_Hal_Property E_Hal_Device_Get_Property_Return;
+typedef struct E_Hal_Bool_Return E_Hal_Device_Query_Capability_Return;
+typedef struct E_Hal_String_List_Return E_Hal_String_List_Return;
+typedef struct E_Hal_String_List_Return E_Hal_Manager_Get_All_Devices_Return;
+typedef struct E_Hal_Bool_Return E_Hal_Manager_Device_Exists_Return;
+typedef struct E_Hal_String_List_Return E_Hal_Manager_Find_Device_String_Match_Return;
+typedef struct E_Hal_String_List_Return E_Hal_Manager_Find_Device_By_Capability_Return;
+
+
+typedef struct E_Hal_UDI_Return E_Hal_Manager_Device_Added;
+typedef struct E_Hal_UDI_Return E_Hal_Manager_Device_Removed;
+typedef struct E_Hal_Capability E_Hal_Manager_New_Capability;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+   EAPI int e_hal_init(void);
+   EAPI int e_hal_shutdown(void);
+
+/* org.freedesktop.Hal.Device */
+   EAPI DBusPendingCall *e_hal_device_get_property(E_DBus_Connection *conn, const char *udi, const char *property, E_DBus_Callback_Func cb_func, void *data);
+   EAPI DBusPendingCall *e_hal_device_get_all_properties(E_DBus_Connection *conn, const char *udi, E_DBus_Callback_Func cb_func, void *data);
+   EAPI DBusPendingCall *e_hal_device_query_capability(E_DBus_Connection *conn, const char *udi, const char *capability, E_DBus_Callback_Func cb_func, void *data);
+
+/* org.freedesktop.Hal.Manager */
+   EAPI DBusPendingCall *e_hal_manager_get_all_devices(E_DBus_Connection *conn, E_DBus_Callback_Func cb_func, void *data);
+   EAPI DBusPendingCall *e_hal_manager_device_exists(E_DBus_Connection *conn, const char *udi, E_DBus_Callback_Func cb_func, void *data);
+   EAPI DBusPendingCall *e_hal_manager_find_device_string_match(E_DBus_Connection *conn, const char *key, const char *value, E_DBus_Callback_Func cb_func, void *data);
+   EAPI DBusPendingCall *e_hal_manager_find_device_by_capability(E_DBus_Connection *conn, const char *capability, E_DBus_Callback_Func cb_func, void *data);
+
+/* utility functions */
+   EAPI void                e_hal_property_free(E_Hal_Property *prop);
+   EAPI const char         *e_hal_property_string_get(E_Hal_Properties *properties, const char *key, int *err);
+   EAPI Eina_Bool           e_hal_property_bool_get(E_Hal_Properties *properties, const char *key, int *err);
+   EAPI int                 e_hal_property_int_get(E_Hal_Properties *properties, const char *key, int *err);
+   EAPI uint64_t            e_hal_property_uint64_get(E_Hal_Properties *properties, const char *key, int *err);
+   EAPI double              e_hal_property_double_get(E_Hal_Properties *properties, const char *key, int *err);
+   EAPI const Eina_List    *e_hal_property_strlist_get(E_Hal_Properties *properties, const char *key, int *err);
+
+/* (un)mount */
+   EAPI DBusPendingCall *e_hal_device_volume_mount(E_DBus_Connection *conn, const char *udi, const char *mount_point, const char *fstype, Eina_List *options, E_DBus_Callback_Func cb_func, void *data);
+   EAPI DBusPendingCall *e_hal_device_volume_unmount(E_DBus_Connection *conn, const char *udi, Eina_List *options, E_DBus_Callback_Func cb_func, void *data);
+   EAPI DBusPendingCall *e_hal_device_volume_eject(E_DBus_Connection *conn, const char *udi, Eina_List *options, E_DBus_Callback_Func cb_func, void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/src/lib/hal/HAL 0.5.10 Specification.html b/src/lib/hal/HAL 0.5.10 Specification.html
new file mode 100644 (file)
index 0000000..f677bb0
--- /dev/null
@@ -0,0 +1,4050 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>HAL 0.5.10 Specification</title><link rel="stylesheet" href="docbook.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.71.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="book" lang="en"><div class="titlepage"><div><div><h1 class="title"><a name="index"></a>HAL 0.5.10 Specification</h1></div><div><div class="authorgroup"><div class="author"><h3 class="author"><span class="firstname">David</span> <span class="surname">Zeuthen</span></h3><div class="affiliation"><div class="address"><p><br>
+           <code class="email">&lt;<a href="mailto:david@fubar.dk">david@fubar.dk</a>&gt;</code><br>
+          </p></div></div></div></div></div><div><p class="releaseinfo">Version 0.5.10</p></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="chapter"><a href="#introduction">1. Introduction</a></span></dt><dd><dl><dt><span class="sect1"><a href="#introduction-about">About</a></span></dt><dt><span class="sect1"><a href="#introduction-acknowledgements">Acknowledgements</a></span></dt><dt><span class="sect1"><a href="#ov_halarch">Architecture of HAL</a></span></dt><dt><span class="sect1"><a href="#introduction-device-objects">Device Objects</a></span></dt><dt><span class="sect1"><a href="#device-capabilities">Device Capabilities</a></span></dt></dl></dd><dt><span class="chapter"><a href="#spec-device-info">2. Device Information Files</a></span></dt><dd><dl><dt><span class="sect1"><a href="#fdi-matching">Matching</a></span></dt><dt><span class="sect1"><a href="#fdi-merging">Merging</a></span></dt><dt><span class="sect1"><a href="#fdi-search-paths">Search Paths</a></span></dt></dl></dd><dt><span class="chapter"><a href="#access-control">3. Access Control</a></span></dt><dd><dl><dt><span class="sect1"><a href="#access-control-device-file">Device Files</a></span></dt><dt><span class="sect1"><a href="#access-control-ipc">D-Bus Interfaces</a></span></dt></dl></dd><dt><span class="chapter"><a href="#locking">4. Locking</a></span></dt><dd><dl><dt><span class="sect1"><a href="#locking-overview">Overview</a></span></dt><dt><span class="sect1"><a href="#locking-guidelines">Guidelines</a></span></dt></dl></dd><dt><span class="chapter"><a href="#device-properties">5. Device Properties</a></span></dt><dd><dl><dt><span class="sect1"><a href="#properties-general">General Properties</a></span></dt><dd><dl><dt><span class="sect2"><a href="#device-properties-info">
+        info namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-info-callouts">Callouts</a></span></dt><dt><span class="sect2"><a href="#device-properties-info-addons">Addons</a></span></dt><dt><span class="sect2"><a href="#device-properties-info-singleton-addons">Singleton Addons</a></span></dt><dt><span class="sect2"><a href="#device-properties-info-method-calls">Method calls</a></span></dt></dl></dd><dt><span class="sect1"><a href="#properties-subsystem">Subsystem-Specific Properties</a></span></dt><dd><dl><dt><span class="sect2"><a href="#device-properties-pci">
+        pci namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-serialif">
+        serial namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-usb">
+        usb_device namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-usbif">
+        usb namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-platform">
+        platform namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ide-host">
+        ide_host namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ide">
+        ide namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-scsi_host">
+        scsi_host namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-scsi">
+        scsi namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ieee1394_host">
+        ieee1394_host namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ieee1394_node">
+        ieee1394_node namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ieee1394">
+        ieee1394 namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-mmc_host">
+        mmc_host namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-mmc">
+        mmc namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ccw">
+        ccw namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ccwgroup">
+        ccwgroup namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-iucv">
+        iucv namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-block">
+        block namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-xen">xen namespace</a></span></dt><dt><span class="sect2"><a href="#device-properties-bluetooth_hci">bluetooth_hci namespace</a></span></dt><dt><span class="sect2"><a href="#device-properties-bluetooth_acl">bluetooth_acl namespace</a></span></dt><dt><span class="sect2"><a href="#device-properties-bluetooth_sco">bluetooth_sco namespace</a></span></dt><dt><span class="sect2"><a href="#device-properties-drm">drm namespace</a></span></dt></dl></dd><dt><span class="sect1"><a href="#properties-functional">Functional Properties</a></span></dt><dd><dl><dt><span class="sect2"><a href="#device-properties-kernel">
+        system namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-volume">
+        volume namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-volume-disc">
+        volume.disc namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-storage">
+        storage namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-storage-cdrom">
+        storage.cdrom namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-storage-linux-raid">
+        storage.linux_raid namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-net">
+        net namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-net-80203">
+        net.80203 namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-net-80211">
+        net.80211 namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-net-bluetooth">
+        net.bluetooth namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-net-irda">
+        net.irda namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-net-80211control">
+        net.80211control namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input">
+        input namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-keys">
+        input.keys namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-keypad">
+        input.keypad namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-keyboard">
+        input.keyboard namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-mouse">
+        input.mouse namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-switch">
+        input.switch namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-joystick">
+        input.joystick namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-tablet">
+        input.tablet namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-keymap">
+        input.keymap namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-xkb">
+        input.xkb namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-pcmcia_socket">
+        pcmcia_socket namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-printer">
+        printer namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-portable_audio_player">
+        portable_audio_player namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-alsa">
+        alsa namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-oss">
+        oss namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-camera">
+        camera namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-scanner">
+        scanner namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-laptop-panel">
+        laptop_panel namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ac_adapter">
+        ac_adapter namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-battery">
+        battery namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-button">
+        button namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-processor">
+        processor namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-light-sensor">
+        light_sensor namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-power-management">
+        power_management namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-tape">
+        tape namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-killswitch">
+        killswitch namespace
+      </a></span></dt></dl></dd><dt><span class="sect1"><a href="#properties-misc">Misc. Properties</a></span></dt><dd><dl><dt><span class="sect2"><a href="#device-properties-access-control">
+        access_control namespace
+      </a></span></dt></dl></dd><dt><span class="sect1"><a href="#properties-deprecated">Deprecated Properties</a></span></dt></dl></dd><dt><span class="chapter"><a href="#interfaces">6. D-Bus interfaces</a></span></dt><dd><dl><dt><span class="sect1"><a href="#interface-manager">org.freedesktop.Hal.Manager interface</a></span></dt><dt><span class="sect1"><a href="#interface-device">org.freedesktop.Hal.Device interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-systempower">org.freedesktop.Hal.Device.SystemPowerManagement interface</a></span></dt><dt><span class="sect1"><a href="#interface-cpufreq">org.freedesktop.Hal.Device.CPUFreq interface</a></span></dt><dt><span class="sect1"><a href="#interface-wakeonlan">org.freedesktop.Hal.Device.WakeOnLan interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-laptop-panel">org.freedesktop.Hal.Device.LaptopPanel interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-keyboard-backlight">org.freedesktop.Hal.Device.KeyboardBacklight interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-light-sensor">org.freedesktop.Hal.Device.LightSensor interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-storage">org.freedesktop.Hal.Device.Storage interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-volume">org.freedesktop.Hal.Device.Volume interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-volume-crypto">org.freedesktop.Hal.Device.Volume.Crypto interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-killswitch">org.freedesktop.Hal.Device.KillSwitch interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-accesscontrol">org.freedesktop.Hal.Device.AccessControl interface</a></span></dt><dt><span class="sect1"><a href="#interface-singleton-addon"><code class="literal">org.freedesktop.Hal.SingletonAddon</code> interface</a></span></dt></dl></dd></dl></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="introduction"></a>Chapter 1. Introduction</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="#introduction-about">About</a></span></dt><dt><span class="sect1"><a href="#introduction-acknowledgements">Acknowledgements</a></span></dt><dt><span class="sect1"><a href="#ov_halarch">Architecture of HAL</a></span></dt><dt><span class="sect1"><a href="#introduction-device-objects">Device Objects</a></span></dt><dt><span class="sect1"><a href="#device-capabilities">Device Capabilities</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="introduction-about"></a>About</h2></div></div></div><p>
+      This document concerns the specification of HAL which is a
+      piece of software that provides a view of the various hardware
+      attached to a system. In addition to this, HAL keeps detailed
+      metadata for each piece of hardware and provide hooks such
+      that system- and desktop-level software can react to changes
+      in the hardware configuration in order to maintain system
+      policy.
+    </p><p>
+      HAL represents a piece of hardware as a <span class="emphasis"><em>device object</em></span>.
+      A device object is identified by a unique identifer and carries a set of
+      key/value paris referred to as <span class="emphasis"><em>device properties</em></span>.
+      Some properties are derived from the actual hardware, some are merged
+      from <span class="emphasis"><em>device information files</em></span>
+      and some are related to the
+      actual device configuration. This document specifies the set
+      of device properties and gives them well-defined meaning. This
+      enable system and desktop level components to distinguish
+      between the different device objects and discover and
+      configure devices based on these properties.
+    </p><p>
+      HAL provides an easy-to-use API through D-Bus which is an IPC
+      framework that, among other things, provides a system-wide
+      message-bus that allows applications to talk to one
+      another. Specifically, D-Bus provides asynchronous
+      notification such that HAL can notify other peers on the
+      message-bus when devices are added and removed as well as when
+      properties on a device are changing.
+    </p><p>
+      The most important goal of HAL is to provide plug-and-play
+      facilities for UNIX-like desktops with focus on providing a
+      rich and extensible description of device characteristics and
+      features. HAL has no other major dependencies apart from D-Bus
+      which, given sufficient infrastructure, allows it to be
+      implemented on many UNIX-like systems. The major focus,
+      initially, is systems running the Linux 2.6 series kernels.
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="introduction-acknowledgements"></a>Acknowledgements</h2></div></div></div><p>
+      Havoc Pennington's article
+      <a href="http://www.ometer.com/hardware.html" target="_top">''Making Hardware Just Work''
+      </a>
+      motivated this work. The specification and software would not exist
+      without all the useful ideas, suggestions, comments and patches
+      from the
+      <a href="http://freedesktop.org/mailman/listinfo/xdg" target="_top">Free Desktop</a> and
+      <a href="http://freedesktop.org/mailman/listinfo/hal" target="_top">HAL</a>
+      mailing lists.
+    </p><p>
+      All trademarks mentioned belong to their respective owners.
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="ov_halarch"></a>Architecture of HAL</h2></div></div></div><p>
+      The HAL consists of a number of components as outlined in the
+      diagram below. Note that this diagram is high-level and doesn't
+      capture all implementation details.
+    </p><p>
+      <img src="hal-arch.png">
+    </p><p>
+      Details on each component
+      </p><div class="itemizedlist"><ul type="disc"><li><p>
+            <span class="emphasis"><em>HAL daemon</em></span>
+          </p><p>
+            A system-wide service that maintains a database of device
+            objects. The daemon is responsible for merging information
+            from device information files and managing the life cycle
+            of device objects. The service is implemented as a daemon
+            and uses helpers to query devices for specific information.
+          </p></li><li><p>
+            <span class="emphasis"><em>Applications</em></span>
+          </p><p>
+            These are applications consuming services from HAL; this
+            includes desktop-wide session daemons for maintaining
+            policy such as power and disk/volume management.
+          </p></li><li><p>
+            <span class="emphasis"><em>Callouts</em></span>
+          </p><p>
+            Callouts are programs that run when device objects are
+            added and removed in the HAL daemon. This is useful for
+            3rd party software to merge additional information onto
+            the device object before it is announced on
+            D-Bus. Callouts are specified on a per-device basis with
+            the <code class="literal">info.callouts.add</code> and
+            <code class="literal">info.callouts.remove</code>. See
+            <a href="#device-properties-info" title="
+        info namespace
+      ">the section called “
+        info namespace
+      ”</a> for details.
+          </p></li><li><p>
+            <span class="emphasis"><em>Methods</em></span>
+          </p><p>
+            It is possible to specify that a given HAL device object
+            implements a specific D-Bus interface,
+            e.g. <code class="literal">org.freedesktop.Hal.Device.Frob</code>
+            with a set of
+            methods <code class="literal">Foo</code>, <code class="literal">Bar</code>
+            and <code class="literal">Baz</code> and have programs run when
+            applications call into this interface. This is defined in
+            the <code class="literal">info.interfaces</code> property, consult
+            <a href="#device-properties-info" title="
+        info namespace
+      ">the section called “
+        info namespace
+      ”</a> for details.
+          </p></li><li><p>
+            <span class="emphasis"><em>Addons</em></span>
+          </p><p>
+            An <span class="emphasis"><em>addon</em></span> can be characterized as a
+            daemon whose life cycle is tied to a device object in
+            HAL. And addon can also <span class="emphasis"><em>claim</em></span> a
+            specific interface on the device object to provide
+            services to applications for configuring / using the
+            device without having to spawn a new program for every
+            method call. HAL provides a facility to launch/destroy one
+            or more addons per device object using
+            the <code class="literal">info.addons</code> property. See
+            <a href="#device-properties-info" title="
+        info namespace
+      ">the section called “
+        info namespace
+      ”</a> for details.
+          </p></li><li><p>
+            <span class="emphasis"><em>Device Information Files</em></span>
+          </p><p>
+            A set of files that matches properties on device objects
+            and merges additional information. These files are used,
+            for among other things, to specify what callouts, methods
+            and addons to associate with a device object. For example,
+            for drives using removable media, HAL includes an add-on
+            daemon which sole purpose is to continously poll the drive
+            to detect media change.
+          </p></li></ul></div><p>
+    </p><p>
+      The D-Bus system message bus is used to provide a ''network
+      API'' to applications. As D-Bus is designed to be language
+      independent, potentially many languages / runtime systems will
+      be able to easily access the services offered by HAL.
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="introduction-device-objects"></a>Device Objects</h2></div></div></div><p>
+      It is important to precisely define the term HAL device
+      object. It's actually a bit blurry to define in general, it
+      includes what most UNIX-like systems consider first class
+      objects when it comes to hardware. In particular, a device
+      object should represent the smallest unit of addressable
+      hardware. This means there can be a one-to-many relationship
+      between a physical device and the device objects exported by
+      HAL. Specifically, a multi-function printer, which appear to
+      users as a single device may show up as several device
+      objects; e.g. one HAL device object for each of the printing,
+      scanning, fax and storage interfaces. Conversely, some devices
+      may be implemented such that the HAL device object represent
+      several functional interfaces. HAL is not concerned with this
+      duality of either one-to-many or many-to-one relationships
+      between device objects and the actual iron constituting what
+      users normally understand as a single piece of hardware;
+      a device object represents the smallest addressable unit.
+    </p><p>
+      Device objects in HAL are organised on a by-connection basis,
+      e.g. for a given device object X it is possible to find the
+      device object Y where X is attached to Y. This gives structure
+      to the device database of HAL; it is possible to map the devices
+      out in a tree. Further, software emulation devices exported by
+      the operating system kernel, such as SCSI emulation for USB
+      Storage Devices, are also considered device objects in HAL. This
+      implies that operating system kernel specific bits leak into the
+      device object database. However applications using HAL will not
+      notice this, such device objects are not referenced anywhere in
+      the device objects that users are interested in; they are merely
+      used as glue to build the device tree.
+    </p><p>
+      In addition to provide information about what kind of hardware a
+      device object represents (such as a PCI or USB device) and how
+      to address it, HAL merges information about the functional
+      interfaces the operating system kernel provides in order to use
+      the device; in most cases this is represented on the device
+      object as a string property with the name of the special device
+      file in
+      <code class="literal">/dev</code>. In addition to the special device file,
+      a number of other useful properties are merged. This means that
+      both hardware and functional properties are on the same device
+      object, which may prove to be useful for an application
+      programmer. For example, an application might query HAL for the
+      device object that exports the special device file
+      <code class="literal">/dev/input/mouse2</code> and learn that this is
+      provide by an USB mouse from a certain manufacturer by
+      checking the properties that export the USB vendor and product
+      identifiers.  See <a href="#device-capabilities" title="Device Capabilities">the section called “Device Capabilities”</a>
+      and
+      <a href="#device-properties" title="Chapter 5. Device Properties">Chapter 5, <i>Device Properties</i></a>
+      for details.
+    </p><p>
+      Finally, HAL provides one or more <span class="emphasis"><em>D-Bus
+      interfaces</em></span> for applications to configure and/or use
+      the device. These interfaces are discussed in
+      <a href="#interfaces" title="Chapter 6. D-Bus interfaces">Chapter 6, <i>D-Bus interfaces</i></a>.
+    </p><p>
+      Summarizing, a device object is comprised by
+    </p><div class="itemizedlist"><ul type="disc"><li><p>
+          <span class="emphasis"><em>UDI</em></span>
+        </p><p>
+          This is the the <span class="emphasis"><em>Unique Device
+          Identifer</em></span>, that is unique for a device object -
+          that is, no other device object can have the same UDI at the
+          same time.  The UDI is computed using bus-specific
+          information and is meant to be unique across device
+          insertions and independent of the physical port or slot the
+          device may be plugged into.
+        </p></li><li><p>
+          <span class="emphasis"><em>Properties</em></span>
+        </p><p>
+          Each device object got a set of properties which are
+          key/value pairs.  The key is an ASCII string while the value
+          can be one of several types, see below. Properties are
+          arranged into name spaces using ''.'' as a separator.
+          </p><div class="itemizedlist"><ul type="circle"><li><p>
+                <code class="literal">string</code> - UTF8 string
+              </p></li><li><p>
+                <code class="literal">strlist</code> - ordered list with UTF8 strings
+              </p></li><li><p>
+                <code class="literal">int</code> - 32-bit signed integer
+              </p></li><li><p>
+                <code class="literal">uint64</code> - 64-bit unsigned integer
+              </p></li><li><p>
+                <code class="literal">bool</code> - truth value
+              </p></li><li><p>
+                <code class="literal">double</code> - IEEE754 double precision
+                floating point number
+              </p></li></ul></div><p>
+        </p></li><li><p>
+          <span class="emphasis"><em>Interfaces</em></span>
+        </p><p>
+          Applications can configure and/or use a device using D-Bus
+          interfaces. Typically, there's a one-to-one relationship
+          between capabilities/namespaces and interfaces.
+        </p></li></ul></div><p>
+      Properties of a device object carry all the important
+      information about a device object. For organisational reasons
+      properties are also namespaced using ''.'' as a separator.
+    </p><p>
+      It can be useful to classify properties into four groups
+    </p><div class="itemizedlist"><ul type="disc"><li><p>Metadata - Information about how the devices
+          are connected with respect to each other
+          (parent/child relationships), what kind of
+          device it is, what functionality it provides
+          etc.
+        </p></li><li><p>Facts -
+          vendor ID, product ID, disk serial numbers,
+          number of buttons on a mouse, formats accepted
+          by a mp3 player and so on.
+        </p></li><li><p>Usage specific information -
+          Network link status, special device file name,
+          filesystem mount location etc.
+        </p></li><li><p>Policy -
+          How the device is to be used be users; usually
+          defined by the system administrator.
+        </p></li></ul></div><p>
+      The first category is determined by HAL, the second category
+      includes information merged from either querying the hardware
+      itself or from device information files. The third category is
+      intercepted by monitoring the hardware and finally the last is
+      merged from files under control of the system
+      administrator. This document is concerned with precisely
+      defining several properties; see
+      <a href="#device-properties" title="Chapter 5. Device Properties">Chapter 5, <i>Device Properties</i></a> and onwards for more
+      information.  As a complement to device properties, HAL also
+      provides <span class="emphasis"><em>conditions</em></span> on HAL device
+      objects. Conditions are used to relay events that are happening
+      on devices which are not easily expressed in properties. This
+      includes events such as ''processor is overheating'' or ''block
+      device unmounted''.
+    </p><p>
+      There is a special hal device object referred to as the ''root
+      computer device object''. This device object represent the
+      entire system as a whole and all other devices are either
+      directly or indirectly childs of this device object. It has
+      the
+      UDI <code class="literal">/org/freedesktop/Hal/devices/computer</code>.
+    </p><p>
+      The fundamental idea about HAL is that all ''interesting''
+      information about hardware that a desktop application needs,
+      can be obtained by querying HAL. Below is a screenshot of a
+      simple device manager application shipped with HAL
+      called <code class="literal">hal-device-manager</code>.  This
+      application is communicating with the HAL daemon and displays
+      the tree of device objects. The shown properties are for a
+      device object representing a harddisk.
+    </p><p>
+      <img src="hal-devices1.png">
+    </p><p>
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="device-capabilities"></a>Device Capabilities</h2></div></div></div><p>
+      Mainstream hardware isn't very good at reporting what it really
+      is, it only reports, at best, how to interact with it. This is a
+      problem; many devices, such as MP3 players or digital still
+      cameras, appear to the operating system as plain USB Mass
+      Storage devices when the device in fact is a lot more than just
+      that. The core of the problem is that without external metadata,
+      the operating system and desktop environment will present it to
+      the user as just e.g. a mass storage device.
+    </p><p>
+      As HAL is concerned with merging of external metadata, through
+      e.g. device information files, there needs to be some scheme on
+      how to record what the device actually is. This is achieved by
+      two textual properties, <code class="literal">info.category</code> and
+      <code class="literal">info.capabilities</code>. The former describes
+      <span class="emphasis"><em>what the device is</em></span> (as a single
+      alphanumeric keyword) and the latter describes
+      <span class="emphasis"><em>what the device does</em></span> (as a number of
+      alphanumeric keywords separated by whitespace). The keywords
+      available for use is defined in this document; we'll refer to
+      them in following simply as <span class="emphasis"><em>capabilities</em></span>.
+    </p><p>
+      HAL itself, assigns capabilities on device detection time by
+      inspecting the device class (if available, it depends on the
+      bus type) and looking at information from the operating system
+      and the hardware itself. 
+    </p><p>
+      User mode drivers such as <code class="literal">libgphoto2</code>
+      and <code class="literal">sane</code> provides device information to
+      merge information about devices they can drive. As such,
+      device objects represent an USB interface gain additional
+      properties such as ''scanner'' or ''camera''.
+    </p><p>
+      Having a capability also means that part of the property
+      namespace, prefixed with the capability name, will be populated
+      with more specific information about the capability. Indeed,
+      some properties may even be required such that applications and
+      device libraries have something to expect. For instance, the
+      capability for being a MP3 player may require properties
+      defining what audio formats the device support (e.g. Ogg and
+      MP3), whether it support recording of audio, and how to interact
+      with the device. For example, the latter may specify ''USB
+      Storage Device'' or ''proprietary protocol, use libfooplayer''.
+    </p><p>
+      Finally, capabilities have an inheritance scheme, e.g. if a device
+      has a capability <code class="literal">foo.bar</code>, it must also have
+      the capability <code class="literal">foo</code>.
+    </p></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="spec-device-info"></a>Chapter 2. Device Information Files</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="#fdi-matching">Matching</a></span></dt><dt><span class="sect1"><a href="#fdi-merging">Merging</a></span></dt><dt><span class="sect1"><a href="#fdi-search-paths">Search Paths</a></span></dt></dl></div><p>
+    Device information files (<code class="literal">.fdi</code> files is a
+    shorthand) are used to merge arbitrary properties onto device
+    objects. The way device information files works is that once all
+    device properties are merged onto a device object it is tried
+    against the set of installed device information files.  Device
+    information files are used for both merging facts and policy
+    settings about devices.
+  </p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="fdi-matching"></a>Matching</h2></div></div></div><p>
+      Each device information file got a number of
+      <code class="literal">&lt;match key="some_property"
+        [string|int|bool|..]="required_value" &gt;
+      </code>
+      directives
+      that is tested against the properties of the device object. If
+      all the match directives passes then the device information can
+      include <code class="literal">&lt;[merge|append|prepend|addset] key="some_property"
+        type="[string|int|bool|..]"&gt;
+      </code>
+      directives to
+      respectively merge new properties or append to existing
+      properties on the device object. It's important to emphasize
+      that any previously property stemming from device detection can
+      be overridden by a device information file.
+    </p><p>
+      The <code class="literal">&lt;match&gt;</code>,
+      <code class="literal">&lt;merge&gt;</code>, <code class="literal">&lt;append&gt;</code>, 
+      <code class="literal">&lt;prepend&gt;</code>
+      and <code class="literal">&lt;addset&gt;</code> directives always
+      requires the <code class="literal">key</code> attribute which must be
+      either a property name on the device object in question or a
+      path to a property on another device object. The latter case is
+      expressed either through direct specification of the UDI, such
+      as
+      <code class="literal">/org/freedesktop/Hal/devices/computer:foo.bar</code>
+      or indirect references such as
+      <code class="literal">@info.parent:baz</code> where the latter means that
+      the device object specified by the UDI in the string property
+      <code class="literal">info.parent</code> should be used to query the
+      property <code class="literal">baz</code>. It is also possible to use
+      multiple indirections, e.g. for a volume on a USB memory stick
+      the indirection <code class="literal">@block.storage_device:@storage.originating_device:usb.vendor_id</code>
+      will reference the <code class="literal">usb.vendor_id</code> property
+      on the device object representing the USB interface.
+    </p><p>
+      When the property to match have been determined a number of
+      attributes can be used within the <code class="literal">&lt;match&gt;</code>
+      tag:
+      </p><div class="itemizedlist"><ul type="disc"><li><p>
+            <code class="literal">string</code> - match a string property; for example
+            <code class="literal">&lt;match key="foo.bar" string="baz"&gt;</code>
+            will match only if 'foo.bar' is a string property assuming the value 'baz'.
+          </p></li><li><p>
+            <code class="literal">string_outof</code> - work like <code class="literal">string</code> but
+           the match is done against a list of strings separated by ';'. 
+           For example: 
+           <code class="literal">&lt;match key="system.hardware.product" string_outof="Satellite A30;Portable PC"&gt;</code>   
+           In this example the line matches if <code class="literal">system.hardware.product</code>
+           is exactly 'Satellite A30' or 'Portable PC'.
+          </p></li><li><p>
+            <code class="literal">int</code> - match an integer property
+          </p></li><li><p>
+            <code class="literal">int_outof</code> - work like <code class="literal">int</code> but
+           the match is done against a list of integer separated by ';'. 
+           For example: 
+           <code class="literal">&lt;match key="usb.product_id" int_outof="0x1007;0x1008;0x1009"&gt;</code>    
+           In this example the line matches if <code class="literal">usb.product_id</code> is 0x1007, 0x1008 or 0x1009.
+          </p></li><li><p>
+            <code class="literal">uint64</code> - match property with the 64-bit unsigned type
+          </p></li><li><p>
+            <code class="literal">bool</code> - match a boolean property
+          </p></li><li><p>
+            <code class="literal">double</code> - match a property of type double
+          </p></li><li><p>
+            <code class="literal">exists</code> - used as
+            <code class="literal">&lt;match key="foo.bar" exists="true"&gt;</code>. Can be used with
+            'true' and 'false' respectively to match when a property exists and it doesn't.
+          </p></li><li><p>
+            <code class="literal">empty</code> - can only be used on string or strlist properties
+            with 'true' and 'false'.
+            The semantics for 'true' is to match only when the string is non-empty.
+          </p></li><li><p>
+            <code class="literal">is_ascii</code> - matches only when a string property
+            contain only ASCII characters. Can be used with 'true' or 'false'.
+          </p></li><li><p>
+            <code class="literal">is_absolute_path</code> - matches only when a string
+            property represents an absolute path (the path doesn't have to exist).
+            Can be used with 'true' or 'false'.
+          </p></li><li><p>
+            <code class="literal">sibling_contains</code> - can only be used with string and
+           strlist (string list).
+            For a string key this matches when a sibling item contains the
+            (sub-)string in the same property. For a string list, this is if a string
+            matches an item in the list.
+          </p></li><li><p>
+            <code class="literal">contains</code> - can only be used with string and
+            strlist (string list).
+            For a string key this matches when the property contains the given
+            (sub-)string. For a string list this match if the given string match
+            a item of the list.
+          </p></li><li><p>
+            <code class="literal">contains_ncase</code> - like <code class="literal">contains</code>
+            but the property and the given key are converted to lowercase before check.
+          </p></li><li><p>
+            <code class="literal">contains_not</code> - can only be used with strlist (string list)
+           and string properties.
+            For a string list this match if the given string not match any of the
+            item of the list (or the property is not set for the device). For a string
+           this match of the property not contains the (sub-)string. You can use this
+           attribute to construct if/else blocks together with e.g. <code class="literal">contains</code>.
+          </p></li><li><p>
+            <code class="literal">contains_outof</code> - like <code class="literal">contains</code> but can be
+           used only with strings and the match is done against a list of (sub-)strings 
+           separated by ';'. 
+           For example: 
+           <code class="literal">&lt;match key="system.hardware.product" contains_outof="D600;D610;C540"&gt;</code>    
+           In this example the line matches if <code class="literal">system.hardware.product</code>
+           contains D600, D610 or C540.
+          </p></li><li><p>
+            <code class="literal">prefix</code> - can only be used with string properties.
+            Matches if property begins with the key.
+          </p></li><li><p>
+            <code class="literal">prefix_ncase</code> - like <code class="literal">prefix</code> but the
+            property and the given key are converted to lowercase before the check.
+          </p></li><li><p>
+            <code class="literal">prefix_outof</code> - like <code class="literal">prefix</code> but the
+           match is done against a list of prefixes separated by ';'. 
+           For example: 
+           <code class="literal">&lt;match key="system.hardware.product" prefix_outof="1860;2366;2371"&gt;</code>      
+           In this example the line matches if <code class="literal">system.hardware.product</code>
+           starts with 1860, 2366 or 2371.
+          </p></li><li><p>
+            <code class="literal">suffix</code> - can only be used with string properties.
+            Matches if property ends with the key.
+          </p></li><li><p>
+            <code class="literal">suffix_ncase</code> - like <code class="literal">suffix</code> but the
+            property and the given key are converted to lowercase before the check.
+          </p></li><li><p>
+            <code class="literal">compare_lt</code> - can be used on int, uint64, double
+            and string properties to compare with a constant.
+            Matches when the given property is less than the given constant
+            using the default ordering.
+          </p></li><li><p>
+            <code class="literal">compare_le</code> - like <code class="literal">compare_lt</code>
+            but matches when less than or equal.
+          </p></li><li><p>
+            <code class="literal">compare_gt</code> - like <code class="literal">compare_lt</code>
+            but matches when greater than.
+          </p></li><li><p>
+            <code class="literal">compare_ge</code> - like <code class="literal">compare_lt</code>
+            but matches when greater than or equal.
+          </p></li><li><p>
+            <code class="literal">compare_ne</code> - like <code class="literal">compare_lt</code>
+            but matches when not equal.
+          </p></li></ul></div><p>
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="fdi-merging"></a>Merging</h2></div></div></div><p>
+
+      The <code class="literal">&lt;merge&gt;</code>, <code class="literal">&lt;append&gt;</code>, 
+      <code class="literal">&lt;prepend&gt;</code>
+      and <code class="literal">&lt;addset&gt;</code> directives all require
+      the <code class="literal">type</code> attribute which specifies what to
+      merge. The following values are supported
+      </p><div class="itemizedlist"><ul type="disc"><li><p>
+            <code class="literal">string</code> - The value is copied to the property. For example
+            <code class="literal">&lt;merge key="foo.bar" type="string"&gt;baz&lt;/merge&gt;</code>
+            will merge the value 'baz' into the property 'foo.bar'.
+          </p></li><li><p>
+            <code class="literal">strlist</code> - For <code class="literal">&lt;merge&gt;</code> the value is
+            copied to the property and the current property will be overwritten. For
+            <code class="literal">&lt;append&gt;</code>
+            and <code class="literal">&lt;prepend&gt;</code> the value is
+            append or prepend to the list as new
+            item. For <code class="literal">&lt;addset&gt;</code> the strlist
+            is treated as a set and the value is appended if, and only
+            if, the value doesn't exist already. Usage of
+           <code class="literal">&lt;copy_property&gt;</code> overwrite the complete list with the 
+           value of the given property to copy from.
+          </p></li><li><p>
+            <code class="literal">bool</code> - Can merge the values 'true' or 'false'
+          </p></li><li><p>
+            <code class="literal">int</code> - Merges an integer
+          </p></li><li><p>
+            <code class="literal">uint64</code> - Merges an unsigned 64-bit integer
+          </p></li><li><p>
+            <code class="literal">double</code> - Merges a double precision floating point number
+          </p></li><li><p>
+            <code class="literal">copy_property</code> - Copies the value of a given
+            property - supports paths with direct and indirect UDI's. For example
+            <code class="literal">&lt;merge key="foo.bar" type="copy_property"&gt;@info.parent:baz.bat&lt;/merge&gt;</code>
+            will merge the value of the property <code class="literal">baz.bat</code> on the device object with the UDI from
+            the property <code class="literal">info.parent</code> into the property <code class="literal">foo.bar</code> on
+            the device object being processed.
+          </p></li></ul></div><p>
+      The <code class="literal">&lt;remove&gt;</code>, directive require only a key and can be used with all keys.
+      For <code class="literal">strlist</code> there is additionally a special syntax to remove a item from the
+      string list. For example to remove item 'bla' from property 'foo.bar':
+      <code class="literal">&lt;remove key="foo.bar" type="strlist"&gt;bla&lt;/remove&gt;</code>
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="fdi-search-paths"></a>Search Paths</h2></div></div></div><p>
+      Device Information files are read from two directories
+      
+      </p><div class="itemizedlist"><ul type="disc"><li><p>
+            <code class="literal">/usr/share/hal/fdi</code> - for files provided by packages
+          </p></li><li><p>
+            <code class="literal">/etc/hal/fdi</code> - for files provided by the system administrator / user
+          </p></li></ul></div><p>
+      
+      in exactly that order. This means that the files provided by the
+      system administrator will be processed last such that they can
+      overwrite / change properties caused by the device information
+      files provided by packages.
+      
+      The following directory structure is used in <code class="literal">/usr/share/hal/fdi</code>
+      
+      </p><div class="itemizedlist"><ul type="disc"><li><p>
+            <code class="literal">information</code> - device information files used to merge device information
+            </p><div class="itemizedlist"><ul type="circle"><li><p>
+                  <code class="literal">10freedesktop</code> - included with the hal package
+                </p></li><li><p>
+                  <code class="literal">20thirdparty</code> - from a 3rd party, not included in hal package
+              </p></li></ul></div><p>
+          </p></li><li><p>
+            <code class="literal">policy</code> - device information files to merge policy properties such as addons or callouts.
+            </p><div class="itemizedlist"><ul type="circle"><li><p>
+                  <code class="literal">10osvendor</code> - included with the hal package
+                </p></li><li><p>
+                  <code class="literal">20thirdparty</code> - from a 3rd party, not included in hal package
+                </p></li></ul></div><p>
+          </p></li><li><p>
+            <code class="literal">preprobe</code> - device information files read before probing devices
+            </p><div class="itemizedlist"><ul type="circle"><li><p>
+                  <code class="literal">10osvendor</code> - included with the hal package
+                </p></li><li><p>
+                  <code class="literal">20thirdparty</code> - from a 3rd party, not included in hal package
+                </p></li></ul></div><p>
+          </p></li></ul></div><p>
+
+      As evident, third party packages should drop device information files in
+
+      </p><div class="itemizedlist"><ul type="disc"><li><p>
+            <code class="literal">/usr/share/hal/fdi/information/20thirdparty</code>
+          </p></li><li><p>
+            <code class="literal">/usr/share/hal/fdi/policy/20thirdparty</code>
+          </p></li><li><p>
+            <code class="literal">/usr/share/hal/fdi/preprobe/20thirdparty</code>
+          </p></li></ul></div><p>
+
+    </p><p>
+      The <code class="literal">/etc/hal/fdi</code> tree uses this layout
+      
+      </p><div class="itemizedlist"><ul type="disc"><li><p>
+            <code class="literal">information</code> - device information files used to merge device information
+          </p></li><li><p>
+            <code class="literal">policy</code> - device information files to merge policy properties such as addons or callouts.
+          </p></li><li><p>
+            <code class="literal">preprobe</code> - device information files to read before probing devices
+          </p></li></ul></div><p>
+      
+      All device information files are matched for every hal device
+      object in the following order.
+
+    </p><div class="orderedlist"><ol type="1"><li><p>
+          When a device is discovered, the <code class="literal">preprobe</code>
+          device information files (e.g. all files
+          from <code class="literal">/usr/share/hal/fdi/preprobe</code>
+          and <code class="literal">/etc/hal/fdi/preprobe</code>) are
+          processed.
+        </p><p> 
+          Typically, this class of device information files is used to
+          tell HAL to leave the device alone by setting the bool
+          property <code class="literal">info.ignore</code> to TRUE. It can also
+          be used to run programs, preprobe callouts, prior to normal
+          device investigation.
+        </p></li><li><p>
+          HAL now runs the preprobe callouts.
+        </p></li><li><p>
+          HAL now probes/investigates the device.
+        </p></li><li><p>
+          All the <code class="literal">information</code> device information
+          files (e.g. all files
+          from <code class="literal">/usr/share/hal/fdi/information</code>
+          and <code class="literal">/etc/hal/fdi/information</code>) are
+          processed.
+        </p><p>
+          These device information files are typically used to
+          associate extra information with a device object.
+        </p></li><li><p>
+          All the <code class="literal">policy</code> policy information
+          files (e.g. all files
+          from <code class="literal">/usr/share/hal/fdi/policy</code>
+          and <code class="literal">/etc/hal/fdi/policy</code>) are
+          processed.
+        </p><p>
+          These device information files are typically used to
+          associate callouts and addons with a device object.
+        </p></li><li><p>
+          HAL now runs the callouts, starts addons, and then finally
+          announces the device on the system message bus.
+        </p></li></ol></div><p>
+
+    </p></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="access-control"></a>Chapter 3. Access Control</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="#access-control-device-file">Device Files</a></span></dt><dt><span class="sect1"><a href="#access-control-ipc">D-Bus Interfaces</a></span></dt></dl></div><p>
+    Access to hardware by unprivileged users is traditionally granted
+    in two ways either by granting access to the <span class="emphasis"><em>special
+    device file</em></span> or allowing access through another process,
+    using IPC acting on behalf of the user. HAL follows the latter
+    model and uses the system-wide message bus (D-Bus) as the IPC
+    mechanism. In addition, HAL has support for modifying the ACL's
+    (access control lists) on a device file to grant/revoke access to
+    users based on several criteria.
+  </p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="access-control-device-file"></a>Device Files</h2></div></div></div><p>
+      If HAL is built with <code class="literal">--enable-acl-management</code>
+      (requires both <code class="literal">--enable-console-kit</code>
+      and <code class="literal">--enable-policy-kit</code>) then ACL's on device
+      objects with the capability <code class="literal">access_control</code>
+      are automatically managed according to the properties defined in
+      <a href="#device-properties-access-control" title="
+        access_control namespace
+      ">the section called “
+        access_control namespace
+      ”</a>. In addition,
+      for this configuration, HAL ships with a device information file
+      (normally installed in
+      <code class="literal">/usr/share/hal/fdi/policy/10osvendor/20-acl-management.fdi</code>)
+      that merges this capability on device objects that are normally
+      accessed by unprivileged users through the device file. This
+      includes e.g. sound cards, webcams and other devices but
+      excludes drives and volumes as the latter two are normally
+      accessed by a user through mounting them into the file system.
+    </p><p>
+      HAL uses PolicyKit to decide what users should have access
+      according to PolicyKit configuration; see the PolicyKit
+      privilege definition
+      file <code class="literal">/etc/PolicyKit/privileges/hal-device-file.priv</code>
+      on a system with HAL installed for the default access suggested
+      by the HAL package and/or OS vendor.
+    </p><p>
+      In addition, 3rd party packages can supply device information
+      files to specify (via
+      the <code class="literal">access_control.grant_user</code>
+      and <code class="literal">access_control.grant_group</code> properties)
+      that a given user or group should always have access to a device
+      file. This is useful for system-wide software (such as AV
+      streaming management) that runs as an unprivileged system
+      user. This interface is supposed to be stable so 3rd party
+      packages can depend on it.
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="access-control-ipc"></a>D-Bus Interfaces</h2></div></div></div><p>
+      If HAL is built without ConsoleKit support
+      (e.g. without <code class="literal">--enable-console-kit</code>) access to
+      the various D-Bus interfaces that provides mechanisms is only
+      protected by the D-Bus security configuration files
+      (e.g. using <code class="literal">at_console</code> to restrict to console
+      user on Red Hat systems) and, in certain cases, restricted to
+      the super user.
+    </p><p>
+      If ConsoleKit support is enabled, access to D-Bus interfaces is
+      currently hardcoded to only allow active users at the system
+      console. If PolicyKit support is enabled, the PolicyKit library
+      will be in charge of determining access; see the PolicyKit
+      privilege definition files
+      in <code class="literal">/etc/PolicyKit/privileges</code> on a system with
+      HAL installed for the default access suggested by the HAL
+      package and/or OS vendor.
+    </p></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="locking"></a>Chapter 4. Locking</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="#locking-overview">Overview</a></span></dt><dt><span class="sect1"><a href="#locking-guidelines">Guidelines</a></span></dt></dl></div><p>
+    As HAL is a mechanism that enables programs in a desktop session
+    to enforce the policy of the users choice, unexpected things can
+    happen. For example, if the user is in the middle of partitioning
+    a disk drive, it is desirable to keep the desktop from mounting
+    partitions that have not yet been prepared with a suitable file
+    system. In fact, in such a situation data loss may be the result
+    if a volume have an old file system signature indicating it's
+    mountable and, simultenously, another tool is writing to the raw
+    block device. The mechanism that automounters use, HAL, provides
+    locking primitives to avoid this.
+  </p><p>
+    Further, for multi-user systems, several desktop sessions may run
+    on a system each on their own display. Suppose that one session
+    becomes idle and the power management daemon in that session
+    decides to suspend the system according to user preferences in the
+    idle session. The result is that users at other seats will see the
+    system suspend and this is not desirable. The power management
+    daemons in all sessions need to cooperate to ensure that the
+    system only suspends when e.g. all sessions are idle or not at
+    all. The mechanism that each power management daemon uses, HAL,
+    provides locking primitives that can be used to achieve this.
+  </p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="locking-overview"></a>Overview</h2></div></div></div><p>
+      HAL provides a mechanism to lock a specific D-Bus interface
+      either for a specific device or for all the devices the caller
+      have access to. 
+    </p><p>
+      The former is achieved by using
+      the <code class="literal">AcquireInterfaceLock()</code>
+      and <code class="literal">ReleaseInterfaceLock()</code> methods on
+      the <code class="literal">org.freedesktop.Hal.Device</code> interface that
+      every device object implements (see
+      <a href="#interface-device" title="org.freedesktop.Hal.Device interface">the section called “org.freedesktop.Hal.Device interface”</a>). By using this API, a caller
+      can prevent any other caller from invoking methods on the given
+      interface for the given device object - other callers will
+      simply see
+      the <code class="literal">org.freedesktop.Hal.Device.InterfaceLocked</code>
+      exception if they attempt to invoke a method on the given
+      interface on the given device. The locker can specify whether
+      the lock is <span class="emphasis"><em>exclusive</em></span> meaning if multiple
+      clients clients can hold the lock or if only one client can hold
+      the lock at one time. If a client don't have access to the
+      interface of the device, attempts to lock will fail with
+      a <code class="literal">org.freedesktop.Hal.PermissionDenied</code>
+      exception. If a client loses access to a device (say, if his
+      session is switched away from using fast user switching) while
+      holding a lock, he will lose the lock; this can be tracked by
+      listening to the <code class="literal">InterfaceLockReleased</code>
+      signal.
+    </p><p>
+      All local clients, whether they are active or not, can always
+      lock interfaces on the root computer device object (this doesn't
+      mean that they are privileged to use the interfaces though) -
+      the rationale is that this device object represents shared
+      infrastructure, e.g. power management, and even inactive
+      sessions needs to participate in managing this.
+    </p><p>
+      If another client already holds a lock exclusively, attempts
+      from other clients to acquire the lock will fail with
+      the <code class="literal">org.freedesktop.Hal.Device.InterfaceAlreadyLocked</code>
+      exception even if they have access to the device.
+    </p><p>
+      In addition, a client may opt to lock all devices that he got
+      access to by using
+      the <code class="literal">AcquireGlobalInterfaceLock()</code>
+      and <code class="literal">ReleaseGlobalInterfaceLock()</code> methods on
+      the <code class="literal">org.freedesktop.Hal.Manager</code> interface on
+      the <code class="literal">/org/freedesktop/Hal/Manager</code> object (see
+      <a href="#interface-manager" title="org.freedesktop.Hal.Manager interface">the section called “org.freedesktop.Hal.Manager interface”</a>). Global interface locks can
+      also be obtained exclusively if the caller so desires. Unlike
+      per-device interface locking, it is not checked at locking time
+      whether the locker have access to a given device; instead
+      checking is done when callers attempt to access the
+      interface.
+    </p><p>
+      The algorithm used for determining if a caller is locked out is
+      shown below. A caller A is locked out of an interface IFACE on a
+      device object DEVICE if, and only if,
+    </p><div class="orderedlist"><ol type="1"><li><p>
+          Another caller B is holding a lock on the interface IFACE on
+          DEVICE and A don't have either a global lock on IFACE or a
+          lock on IFACE on DEVICE; or
+        </p></li><li><p>
+          Another caller B is holding the global lock on the
+          interface IFACE and B has access to DEVICE and and A don't
+          have either a global lock on IFACE or a lock on IFACE on
+          DEVICE.
+        </p></li></ol></div><p>
+      In other words, a caller A can grab a global lock, but that
+      doesn't mean A can lock other clients out of devices that A
+      doesn't have access to. Specifically a caller is never locked
+      out if he has locked an interface either globally or on the
+      device in question. However, if two clients have a lock on a
+      device, then both can access it. To ensure that everyone is
+      locked out, a caller needs to use an exclusive lock.
+    </p><p>
+      Note that certain interfaces will also check whether other locks
+      are being held on other device objects. This is specified on a
+      per-interface basis in <a href="#interfaces" title="Chapter 6. D-Bus interfaces">Chapter 6, <i>D-Bus interfaces</i></a>.
+    </p><p>
+      If a process holding locks disconnects from the system bus, the
+      locks being held by that process will be released.
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="locking-guidelines"></a>Guidelines</h2></div></div></div><p>
+      Locking is only useful if applications requiring exclusive
+      access actually use the locking primitives to cooperate with
+      other applications. Here is a list of guidelines.
+    </p><div class="itemizedlist"><ul type="disc"><li><p>
+          <span class="emphasis"><em>Disk Management / Partitioning</em></span>
+        </p><p>
+          In order to prevent HAL-based automounters from mounting
+          partitions that are being prepared, applications that access
+          block devices directly (and pokes the kernel to reload the
+          partitioning table) should lock out automounters by either
+          a) obtaining
+          the <code class="literal">org.freedesktop.Hal.Device.Storage</code>
+          lock on each drive being processed; or b) obtaintaing the
+          global
+          <code class="literal">org.freedesktop.Hal.Device.Storage</code>
+          lock. This includes programs like fdisk, gparted, parted and
+          operating system installers. See also
+          <a href="#interface-device-volume" title="org.freedesktop.Hal.Device.Volume interface">the section called “org.freedesktop.Hal.Device.Volume interface”</a> and
+          the <code class="literal">hal-lock</code>(1) program and manual page.
+        </p></li><li><p>
+          <span class="emphasis"><em>Power Management</em></span>
+        </p><p>
+          Typically, a desktop session includes a session-wide power
+          management daemon that enforces the policy of the users
+          choice, e.g. whether the system should suspend to ram on lid
+          close, whether to hibernate the system after the user being
+          idle for 30 minutes and so on. In a multi-user setup (both
+          fast user switching and multi-seat), this can break in
+          various interesting ways unless the power management daemons
+          cooperate. Also, there may be software running at the system
+          level who will want to inhibit a desktop session power
+          management daemon from suspending / shutting down.
+        </p><div class="itemizedlist"><ul type="circle"><li><p>
+              System-level software that do not wish to be interrupted
+              by the effect of someone calling into the
+              <code class="literal">org.freedesktop.Hal.Device.SystemPowerManagement</code>
+              interface MUST hold the
+              <code class="literal">org.freedesktop.Hal.Device.SystemPowerManagement</code>
+              lock non-exclusively on the root computer device
+              object. For example, the YUM software updater should
+              hold the lock when doing an RPM transaction.
+            </p></li></ul></div><p>
+          In addition, any power management session daemon instance
+        </p><div class="itemizedlist"><ul type="circle"><li><p>
+              ... MUST hold the <code class="literal">org.freedesktop.Hal.Device.SystemPowerManagement</code> lock
+              non-exclusively on the root computer device object
+              unless it is prepared to call into this interface
+              itself. This typically means that the PM daemon instance
+              simply acquires the lock on start up and releases it
+              just before it calls into
+              the <code class="literal">org.freedesktop.Hal.Device.SystemPowerManagement</code>
+              interface. In other words, the PM daemon instance needs
+              to hold the lock exactly when it doesn't want other PM
+              daemon instances to call into
+              the <code class="literal">org.freedesktop.Hal.Device.SystemPowerManagement</code> interface.
+              This means that if the user have configured the PM
+              daemon instance to go to sleep after 30 minutes of
+              inactivity, the lock should be released then.
+            </p></li><li><p>
+              ... MUST not hold the lock when the session is inactive
+              (fast user switching) UNLESS an application in the
+              session have explicitly called Inhibit() on
+              the <code class="literal">org.freedesktop.PowerManagement</code>
+              D-Bus session bus interface of the PM daemon.
+            </p></li><li><p>
+              ... MUST check that no other process is holding the lock (using the <code class="literal">IsLockedByOthers</code> method on the standard <code class="literal">org.freedesktop.Hal.Device</code> interface)
+              before calling into
+              the <code class="literal">org.freedesktop.Hal.Device.SystemPowerManagement</code>
+              interface. If another process is holding the lock, it
+              means that either 1) another session is not prepared to
+              call into
+              the <code class="literal">org.freedesktop.Hal.Device.SystemPowerManagement</code>
+              interface; OR 2) some system-level software is holding
+              the lock. The PM daemon instance MUST respect this by
+              not calling into
+              the <code class="literal">org.freedesktop.Hal.Device.SystemPowerManagement</code>
+              interface itself.
+            </p></li></ul></div><p>
+          However, any Power management daemon instance
+        </p><div class="itemizedlist"><ul type="circle"><li><p>
+              ... MAY prompt the user, if applicable, to ask if she
+              still wants to perform the requested action (e.g. call
+              into
+              the <code class="literal">org.freedesktop.Hal.Device.SystemPowerManagement</code>
+              interface) despite the fact that another process
+              (possibly from another user) is indicating that it does
+              not want the system to e.g. suspend. Only if the user
+              agrees, the power management instance should call into
+              the <code class="literal">org.freedesktop.Hal.Device.SystemPowerManagement</code>
+              interface. Typically, it's only useful to prompt the
+              user with such questions if the request to call into
+              the <code class="literal">org.freedesktop.Hal.Device.SystemPowerManagement</code>
+              interface originates from user input, e.g. either a
+              hotkey, the user clicking a suspend button in the UI or
+              an application invoking the <code class="literal">Suspend()</code> method on the 
+              <code class="literal">org.freedesktop.PowerManagement</code> D-Bus
+              session interface of the PM daemon.
+            </p></li><li><p>
+              ... MAY ignore that other processes are holding the lock
+              and call into
+              the <code class="literal">org.freedesktop.Hal.Device.SystemPowerManagement</code>
+              interface anyway, but ONLY if if the request to call
+              into
+              the <code class="literal">org.freedesktop.Hal.Device.SystemPowerManagement</code>
+              interface originated from e.g. lid close, critically low
+              battery or other similar conditions.
+            </p></li><li><p>
+              ... MAY still call <code class="literal">SetPowerSave()</code> on
+              the <code class="literal">org.freedesktop.Hal.Device.SystemPowerManagement</code>
+              interface even if other processes are holding the lock.
+            </p></li></ul></div></li></ul></div></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="device-properties"></a>Chapter 5. Device Properties</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="#properties-general">General Properties</a></span></dt><dd><dl><dt><span class="sect2"><a href="#device-properties-info">
+        info namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-info-callouts">Callouts</a></span></dt><dt><span class="sect2"><a href="#device-properties-info-addons">Addons</a></span></dt><dt><span class="sect2"><a href="#device-properties-info-singleton-addons">Singleton Addons</a></span></dt><dt><span class="sect2"><a href="#device-properties-info-method-calls">Method calls</a></span></dt></dl></dd><dt><span class="sect1"><a href="#properties-subsystem">Subsystem-Specific Properties</a></span></dt><dd><dl><dt><span class="sect2"><a href="#device-properties-pci">
+        pci namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-serialif">
+        serial namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-usb">
+        usb_device namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-usbif">
+        usb namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-platform">
+        platform namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ide-host">
+        ide_host namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ide">
+        ide namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-scsi_host">
+        scsi_host namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-scsi">
+        scsi namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ieee1394_host">
+        ieee1394_host namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ieee1394_node">
+        ieee1394_node namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ieee1394">
+        ieee1394 namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-mmc_host">
+        mmc_host namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-mmc">
+        mmc namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ccw">
+        ccw namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ccwgroup">
+        ccwgroup namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-iucv">
+        iucv namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-block">
+        block namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-xen">xen namespace</a></span></dt><dt><span class="sect2"><a href="#device-properties-bluetooth_hci">bluetooth_hci namespace</a></span></dt><dt><span class="sect2"><a href="#device-properties-bluetooth_acl">bluetooth_acl namespace</a></span></dt><dt><span class="sect2"><a href="#device-properties-bluetooth_sco">bluetooth_sco namespace</a></span></dt><dt><span class="sect2"><a href="#device-properties-drm">drm namespace</a></span></dt></dl></dd><dt><span class="sect1"><a href="#properties-functional">Functional Properties</a></span></dt><dd><dl><dt><span class="sect2"><a href="#device-properties-kernel">
+        system namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-volume">
+        volume namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-volume-disc">
+        volume.disc namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-storage">
+        storage namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-storage-cdrom">
+        storage.cdrom namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-storage-linux-raid">
+        storage.linux_raid namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-net">
+        net namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-net-80203">
+        net.80203 namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-net-80211">
+        net.80211 namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-net-bluetooth">
+        net.bluetooth namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-net-irda">
+        net.irda namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-net-80211control">
+        net.80211control namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input">
+        input namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-keys">
+        input.keys namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-keypad">
+        input.keypad namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-keyboard">
+        input.keyboard namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-mouse">
+        input.mouse namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-switch">
+        input.switch namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-joystick">
+        input.joystick namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-tablet">
+        input.tablet namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-keymap">
+        input.keymap namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-input-xkb">
+        input.xkb namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-pcmcia_socket">
+        pcmcia_socket namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-printer">
+        printer namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-portable_audio_player">
+        portable_audio_player namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-alsa">
+        alsa namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-oss">
+        oss namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-camera">
+        camera namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-scanner">
+        scanner namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-laptop-panel">
+        laptop_panel namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-ac_adapter">
+        ac_adapter namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-battery">
+        battery namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-button">
+        button namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-processor">
+        processor namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-light-sensor">
+        light_sensor namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-power-management">
+        power_management namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-tape">
+        tape namespace
+      </a></span></dt><dt><span class="sect2"><a href="#device-properties-killswitch">
+        killswitch namespace
+      </a></span></dt></dl></dd><dt><span class="sect1"><a href="#properties-misc">Misc. Properties</a></span></dt><dd><dl><dt><span class="sect2"><a href="#device-properties-access-control">
+        access_control namespace
+      </a></span></dt></dl></dd><dt><span class="sect1"><a href="#properties-deprecated">Deprecated Properties</a></span></dt></dl></div><p>
+    Properties are arranged in a namespaces using ''.'' as a separator
+    and are key/value pairs. The value may assume different types; currently
+    int32, double, bool, UTF8 strings and UTF8 string lists are supported.
+    The key of a property is always an ASCII string without any whitespace.
+    When a property changes, HAL will emit a D-Bus signal that applications
+    can catch.
+  </p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="properties-general"></a>General Properties</h2></div></div></div><p>
+      The section represents properties that aren't tied to either
+      physical or functional characteristics of what the device
+      object represents.
+    </p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-info"></a>
+        info namespace
+      </h3></div></div></div><p>
+        The <code class="literal">info</code> namespace contain properties that
+        can be considered metadata about device objects. These
+        properties are always available.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">info.subsystem</code> (string)
+              </td><td>pci, usb, ide_host, ide, block, usb, usbif, scsi_host, scsi</td><td>Yes</td><td>Describes what subsystem the device is connected to</td></tr><tr><td>
+                <code class="literal">info.udi</code> (string)
+              </td><td>example: /org/freedesktop/Hal/devices/pci_10ec_8139</td><td>Yes</td><td>The HAL unique device id</td></tr><tr><td>
+                <code class="literal">info.capabilities</code> (strlist)
+              </td><td>example: 'block, storage, storage.cdrom'</td><td>No</td><td>A string list of capabilities describing what the devices does</td></tr><tr><td>
+                <code class="literal">info.category</code> (string)
+              </td><td>example: storage.cdrom</td><td>No</td><td>The prominent capability describing what the device is</td></tr><tr><td>
+                <code class="literal">info.product</code> (string)
+              </td><td>examples: ''SleekKeyboard'', ''MouseMan 2003'', ''Volume'', ''LS-120 SLIM3 00 UHD Floppy''</td><td>No</td><td>The name of the device; should not be used in any UI; use subsystem / capability specific properties instead.</td></tr><tr><td>
+                <code class="literal">info.vendor</code> (string)
+              </td><td>examples: Logitch, Mustek</td><td>No</td><td>The name of the vendor of the device; should not be used in any UI; use subsystem / capability specific properties instead.</td></tr><tr><td>
+                <code class="literal">info.parent</code> (string)
+              </td><td>example: /org/freedesktop/Hal/devices/computer</td><td>Yes, for all non-root device objects</td><td>The UDI of the device object that this device object
+                is connected to.
+              </td></tr><tr><td>
+                <code class="literal">info.locked</code> (bool)
+              </td><td> </td><td>No</td><td>
+                If this property is available and set
+                to <code class="literal">TRUE</code> it means that a process
+                is using the device that the hal device object in
+                question represents and no other process should attempt
+                to use or configure the device. The lock is only
+                advisory.
+              </td></tr><tr><td>
+                <code class="literal">info.locked.reason</code> (string)
+              </td><td>
+                example: ''The optical drive is currently being used to
+                record a CD-RW disc.''
+              </td><td>
+                Only available if <code class="literal">info.locked</code> is set
+                to <code class="literal">TRUE</code>.
+              </td><td>A localized text suitable for UI display</td></tr><tr><td>
+                <code class="literal">info.locked.dbus_service</code> (string)
+              </td><td>example: :1.278</td><td>
+                Only available if <code class="literal">info.locked</code> is set
+                to <code class="literal">TRUE</code>.
+              </td><td>The base D-BUS service of the process holding the lock.</td></tr><tr><td>
+                <code class="literal">info.is_recalled</code> (bool)
+              </td><td> </td><td>No</td><td>
+                This is set if the hardware may be recalled and should
+                be checked for any potential problem.
+              </td></tr><tr><td>
+                <code class="literal">info.recall.vendor</code> (string)
+              </td><td>Dell, Sony, HP, Panasonic, etc.</td><td>Yes, if <code class="literal">info.is_recalled</code> is TRUE</td><td>
+                The vendor responsible for the hardware recall.
+              </td></tr><tr><td>
+                <code class="literal">info.recall.website_url</code> (string)
+              </td><td> </td><td>Yes, if <code class="literal">info.is_recalled</code> is TRUE</td><td>
+                Users should check this website for more details and if their
+                hardware may affected by any possible fault.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-info-callouts"></a>Callouts</h3></div></div></div><p>
+        Callouts are programs invoked when the device object are added
+        and removed. As such, callouts can be used to maintain
+        system-wide policy (that may be specific to the particular OS)
+        such as changing permissions on device nodes, updating the
+        systemwide
+        <code class="literal">/etc/fstab</code> file or configuring the networking
+        subsystem.
+      </p><p>
+        There are three different classes of callouts. A callout
+        involves sequentially invoking all executable programs in the
+        string list in listed order.
+      </p><p>
+        All callouts are searched for and execute in a minimal
+        environment. In addition, the UDI of the device object is
+        exported in the environment
+        variable <code class="literal">UDI</code>. All properties of the device
+        object are exported in the environment prefixed
+        with <code class="literal">HAL_PROP_</code>. If a device is added or
+        removed is exported in the environment
+        variable <code class="literal">HALD_ACTION
+        </code>. The search path for the callout includes the
+        following paths:
+      </p><div class="orderedlist"><ol type="1"><li><p>
+            <code class="literal">$libexecdir</code> (typically <code class="literal">/usr/libexec</code> (e.g. Red Hat) or  <code class="literal">/usr/lib/hal</code> (e.g. Debian))
+          </p></li><li><p>
+            <code class="literal">$libdir/hal/scripts</code> (typically <code class="literal">/usr/lib/hal/scripts</code> or 
+            <code class="literal">/usr/lib64/hal/scripts</code>)
+          </p></li><li><p>
+            <code class="literal">$bindir/</code> (typically <code class="literal">/usr/bin</code>)
+          </p></li></ol></div><p>
+        including $PATH the HAL daemon was started with during system
+        initialization. Depending on the distribution, this typically
+        includes <code class="literal">/sbin</code>, 
+        <code class="literal">/usr/sbin</code>, 
+        <code class="literal">/bin</code>, 
+        <code class="literal">/usr/sbin</code>. If the program to run is not
+        found in any of these paths, the it <span class="emphasis"><em>will
+        not</em></span> run even if the given path is absolute. To be
+        portable across operating systems, third party packages
+        providing callouts must therefore only
+        use <code class="literal">$libdir/hal/scripts</code>.
+      </p><p>
+        If ConsoleKit support is enabled, the variables
+        <code class="literal">CK_NUM_SEATS</code> (number of seats),        
+        <code class="literal">CK_NUM_SESSIONS</code> (number of sessions),        
+        <code class="literal">CK_SEATS</code> (tab sep. list of seat-id's),
+        <code class="literal">CK_SEAT_seat-id</code> (tab sep. list of session-id's for a seat),
+        <code class="literal">CK_SEAT_NUM_SESSIONS_seat-id</code> (number of sessions on a seat),        
+        <code class="literal">CK_SESSION_SEAT_session-id</code> (the seat that a session belongs to) and
+        <code class="literal">CK_SESSION_IS_ACTIVE_session-id</code> (whether a given session is active) and
+        <code class="literal">CK_SESSION_UID_session-id</code> (the user of the session) and
+        <code class="literal">CK_SESSION_IS_LOCAL_session-id</code> (whether a session is local),
+        <code class="literal">CK_SESSION_HOSTNAME_session-id</code> (host name of session's display if it's not local),
+        will be exported as well. Example:
+      </p><pre class="programlisting">
+CK_NUM_SEATS=1
+CK_NUM_SESSIONS=2
+CK_SEATS=Seat1
+CK_SEAT_Seat1=Session1  Session3
+CK_SEAT_NUM_SESSIONS_Seat1=2
+CK_SESSION_IS_ACTIVE_Session1=true
+CK_SESSION_IS_ACTIVE_Session3=false
+CK_SESSION_IS_LOCAL_Session1=true
+CK_SESSION_IS_LOCAL_Session3=true
+CK_SESSION_SEAT_Session1=Seat1
+CK_SESSION_SEAT_Session3=Seat1
+CK_SESSION_UID_Session1=500
+CK_SESSION_UID_Session3=501
+      </pre><p>
+        Note that all ConsoleKit object paths given are just base
+        names; the real D-Bus object path can be reconstructed by
+        appending <code class="literal">/org/freedesktop/ConsoleKit/</code>
+        prepended to the given identifer.
+      </p><p>
+        The HAL daemon is not suspended while callouts are executing. Thus,
+        callouts can communicate with the HAL daemon using the D-BUS network
+        API. Hence, one application of callouts is to merge or modify
+        properties on a device object.
+      </p><p>
+        To reduce round trips and increase privacy, callouts can (and
+        should) communicate with the HAL daemon using a peer to peer
+        D-Bus connection specified by
+        the <code class="literal">HALD_DIRECT_ADDR</code> environment
+        variable. There is convience API in libhal to do this.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">info.callouts.add</code> (string list)
+              </td><td> </td><td>No</td><td>
+                A string list with the programs which should be
+                executed (with <code class="literal">HALD_ACTION=add</code>)
+                when the device is added to the GDL (global device
+                list) but just before it is announced through the
+                D-BUS network API.
+              </td></tr><tr><td>
+                <code class="literal">info.callouts.remove</code> (string list)
+              </td><td> </td><td>No</td><td>
+                A string list with the programs that should be
+                executed (with <code class="literal">HALD_ACTION=remove</code>)
+                when the device is removed from the GDL (global device
+                list). The device isn't removed before the last
+                callout has finished.
+              </td></tr><tr><td>
+                <code class="literal">info.callouts.preprobe</code> (string list)
+              </td><td> </td><td>No</td><td>
+                A string list with the programs that should be
+                executed
+                (with <code class="literal">HALD_ACTION=preprobe</code>) before
+                the device is probed (e.g. investigated) and can be
+                used to avoid causing unnecessary I/O.
+              </td></tr><tr><td>
+                <code class="literal">info.callouts.session_add</code> (string list)
+              </td><td> </td><td>No</td><td>
+                A string list with all programs that should be
+                executed
+                (with <code class="literal">HALD_ACTION=session_add</code>) when
+                a session is added. Can only be set on the root
+                computer device object.  The environment also contains
+                the variables
+               <code class="literal">HALD_SESSION_ADD_SESSION_ID</code>, 
+               <code class="literal">HALD_SESSION_ADD_SESSION_UID</code> and
+               <code class="literal">HALD_SESSION_ADD_SESSION_IS_ACTIVE</code>
+               to identify the session. This is only used when HAL is
+               built with ConsoleKit support.
+              </td></tr><tr><td>
+                <code class="literal">info.callouts.session_remove</code> (string list)
+              </td><td> </td><td>No</td><td>
+                A string list with all programs which should be
+                executed
+                (with <code class="literal">HALD_ACTION=session_remove</code>)
+                when a session is removed. Can only be set on the root
+                computer device object.  The environment also contains
+                the variables
+               <code class="literal">HALD_SESSION_REMOVE_SESSION_ID</code>, 
+               <code class="literal">HALD_SESSION_REMOVE_SESSION_UID</code> and
+               <code class="literal">HALD_SESSION_REMOVE_SESSION_IS_ACTIVE</code>
+               to identify the session. This is only used when HAL is
+               built with ConsoleKit support.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-info-addons"></a>Addons</h3></div></div></div><p>
+        Addons are programs that run for the life time of the device
+        object. They are searched for and execute in the same
+        environment as callouts
+        (e.g. with <code class="literal">HAL_PROP_*</code> set in the
+        environment to represent the device properties) and are
+        launched just before the device is announced on D-Bus (but
+        just after the last add callouts have finished). When the
+        device object goes away, HAL will send
+        a <code class="literal">SIGTERM</code> to the process.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">info.addons</code> (strlist)
+              </td><td> </td><td>No</td><td>
+                List of programs to run when device is added. Each
+                program will need to call
+                the <code class="literal">AddonIsReady()</code> method in order
+                for the device to show up on D-Bus.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-info-singleton-addons"></a>Singleton Addons</h3></div></div></div><p>
+        Singleton Addons are programs that are started by HAL to
+        handle a set of devices. They are identified by the command line
+        used to start them. They MUST implement the
+       <a href="#interface-singleton-addon" title="org.freedesktop.Hal.SingletonAddon interface">
+         <code class="literal">org.freedesktop.Hal.SingletonAddon</code>
+       </a>
+       interface.  on the path
+       <code class="literal">/org/freedesktop/Hal/Singleton</code> path on
+        the direct connection to the HAL daemon.
+      </p><p>
+        When a device is added with an <code class="literal">info.addons.singleton</code>
+        string list key, the elements of that key are used as the command line
+        to start the singleton if the singleton is not already running.
+        Once the singleton has called <code class="literal">SingletonAddonIsReady</code> on
+       <a href="#interface-manager" title="org.freedesktop.Hal.Manager interface">
+         <code class="literal">org.freedesktop.Hal.Manager</code>
+       </a> interface, it will receive
+       <code class="literal">DeviceAdded</code> calls on its
+       <a href="#interface-singleton-addon" title="org.freedesktop.Hal.SingletonAddon interface">
+         <code class="literal">org.freedesktop.Hal.SingletonAddon</code>
+       </a>
+        interface for all devices that have
+        its commandline in <code class="literal">info.addons.singletona</code>.
+      </p><p>
+        If a device is added and the singleton specified in
+        <code class="literal">info.addons.singleton</code> is already running, the
+        singleton will recieve <code class="literal">DeviceAdded</code> on its
+       <a href="#interface-singleton-addon" title="org.freedesktop.Hal.SingletonAddon interface">
+         <code class="literal">org.freedesktop.Hal.SingletonAddon</code>
+       </a>
+       interface for that new device.  </p><p>
+        When a device is removed that is being handled by a singleton, the
+       singleton will recieve <code class="literal">DeviceRemoved</code> on
+       <a href="#interface-singleton-addon" title="org.freedesktop.Hal.SingletonAddon interface">
+         <code class="literal">org.freedesktop.Hal.SingletonAddon</code>
+       </a>.
+       When it is no longer handling any more devices it should exit cleanly.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">info.addons.singleton</code> (strlist)
+              </td><td> </td><td>No</td><td>
+                A list of commandlines for singleton addons which should
+                service this device.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-info-method-calls"></a>Method calls</h3></div></div></div><p>
+        Method calls on a specific interface on a device object can be
+        implemented by the HAL daemon running a program. Note that
+        this is not the only way to implement support for method
+        calls; if you expect a lot of method calls it is preferable to
+        implement an addon and use
+        the <code class="literal">ClaimInterface()</code> API since it reduces
+        the overhead of spawning a process and it can handle both
+        complex incoming and return types as well. See <a href="#interface-device" title="org.freedesktop.Hal.Device interface">the section called “org.freedesktop.Hal.Device interface”</a> for
+        details on claiming interfaces via an addon..
+      </p><p>
+        Note that method calls implemented via running a program are
+        limited to the return type being an a signed 32-bit integer
+        (this will change in a future release). The incoming
+        parameters are limited to only basic types and arrays of
+        strings. The parameters are passed via stdin using a textual
+        representation. As such, there is a lot of overhead with
+        handling method calls by spawning programs and as such it
+        should only be used for situtations where the nature of the
+        method call is that it will not be frequently used.
+      </p><p>
+        As with addons, method calls are searched for and execute in
+        the same minimal environment as callouts
+        (e.g. with <code class="literal">HAL_PROP_*</code> set in the
+        environment to represent the device properties) and in
+        addition the environment variables
+        <code class="literal">HAL_METHOD_INVOKED_BY_UID</code> (the uid of the caller)
+        and
+        <code class="literal">HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME</code>
+        (the unique system bus connection name of the caller) are
+        set. Additionally, if HAL is built with ConsoleKit support, 
+        <code class="literal">HAL_METHOD_INVOKED_BY_PID</code> and
+        <code class="literal">HAL_METHOD_INVOKED_BY_SELINUX_CONTEXT</code> (but
+        only if the running system have SELinux enabled) will be
+        set. If HAL itself, or a HAL addon, is invoking a method, then
+        these variables will not be present. Here's an example
+      </p><pre class="programlisting">
+HAL_METHOD_INVOKED_BY_UID=500
+HAL_METHOD_INVOKED_BY_PID=22553
+HAL_METHOD_INVOKED_BY_SELINUX_CONTEXT=user_u:system_r:unconfined_t
+HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME=:1.138
+      </pre><p>
+        In addition, with ConsoleKit
+        support, <code class="literal">HAL_METHOD_INVOKED_BY_SESSION</code> will
+        be set to (the basename) of the ConsoleKit session object path
+        but only if the caller is in a session. The method handler can
+        then use the previously
+        mentioned <code class="literal">CK_SESSION_*</code> to learn everything
+        about the context of the caller.
+        
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">info.interfaces</code> (strlist)
+              </td><td> </td><td>No</td><td>
+                A list of D-Bus interfaces that the device object
+                supports apart from the
+                standard <code class="literal">org.freedesktop.Hal.Device</code>
+                interface.
+              </td></tr><tr><td>
+                <code class="literal">&lt;iface&gt;.method_names</code> (strlist)
+              </td><td>example: <code class="literal">'Foo', 'Bar', 'Baz'</code></td><td>No</td><td>
+                If a D-Bus interface is implemented by executing a
+                program for every method, this property contains an
+                ordered list of the method names. 
+              </td></tr><tr><td>
+                <code class="literal">&lt;iface&gt;.method_argnames</code> (strlist)
+              </td><td>example: <code class="literal">'foo_arg1 foo_arg2', '', 'baz_arg1'</code></td><td>No</td><td>
+                This property contains the names of the arguments for
+                each method. Each entry is a white-space separated
+                list for that particular method.
+              </td></tr><tr><td>
+                <code class="literal">&lt;iface&gt;.method_signatures</code> (strlist)
+              </td><td>example: <code class="literal">'si', '', 'as'</code></td><td>No</td><td>
+                This property contains the D-Bus signature for each
+                method. The signature should only cover incoming
+                arguments; each method is defined as returning an
+                integer.
+              </td></tr><tr><td>
+                <code class="literal">&lt;iface&gt;.method_execpaths</code> (strlist)
+              </td><td>example: <code class="literal">'foo-binary', 'bar-binary', 'baz-binary'</code></td><td>No</td><td>
+                This property contains the name of the program to
+                execute when this method is called. The return code
+                of the program will be passed as the integer result
+                to the D-Bus caller. 
+                
+                If a program wants to return an error, it just needs
+                to write two lines to stderr; the first line is the
+                exception name to throw and the second line is the
+                exception detail.
+              </td></tr></tbody></table></div><p>
+        Items in the <code class="literal">&lt;iface&gt;.*</code> clearly must
+        correspond with each other. The whole mechanism is best
+        explained by an example:
+          
+        </p><pre class="programlisting">
+info.interfaces = {'org.freedesktop.Hal.Device.Volume'}
+org.freedesktop.Hal.Device.Volume.method_argnames = {'mount_point fstype extra_options', 'extra_options', 'extra_options'}
+org.freedesktop.Hal.Device.Volume.method_execpaths = {'hal-storage-mount', 'hal-storage-unmount', 'hal-storage-eject'}
+org.freedesktop.Hal.Device.Volume.method_names = {'Mount', 'Unmount', 'Eject'}
+org.freedesktop.Hal.Device.Volume.method_signatures = {'ssas', 'as', 'as'}
+        </pre><p>
+        
+        which, for example, shows that the <code class="literal">Mount()</code>
+        method on the
+        interface <code class="literal">org.freedesktop.Hal.Device.Volume</code>
+        takes three arguments: <code class="literal">mount_point</code> (a
+        string), <code class="literal">fstype</code> (a string)
+        and <code class="literal">extra_options</code> (an array of strings).
+        
+      </p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="properties-subsystem"></a>Subsystem-Specific Properties</h2></div></div></div><p>
+      In this section properties for device objects that represent
+      addressable hardware is described. Availability of
+      these depends on the value of the <code class="literal">info.subsystem</code>
+      property.  These properties are not of particular interest to
+      application developers, instead they are useful for libraries
+      and userspace drivers that needs to interact with the device
+      given a UDI. Knowledge of various subsystem-specific
+      technologies is assumed for this section to be useful.
+    </p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-pci"></a>
+        pci namespace
+      </h3></div></div></div><p>
+        This namespace contains properties for device objects representing
+        functions on devices on a PCI bus. These properties are available
+        exactly when <code class="literal">info.subsystem</code> equals <code class="literal">pci</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">pci.device_class</code> (int)
+              </td><td>example: 3</td><td>Yes</td><td>Device Class</td></tr><tr><td>
+                <code class="literal">pci.device_subclass</code> (int)
+              </td><td>example: 0</td><td>Yes</td><td>PCI Device Sub Class</td></tr><tr><td>
+                <code class="literal">pci.device_protocol</code> (int)
+              </td><td>example: 0</td><td>Yes</td><td>Device Protocol</td></tr><tr><td>
+                <code class="literal">pci.product_id</code> (int)
+              </td><td>example: 0x4c4d</td><td>Yes</td><td>Product ID</td></tr><tr><td>
+                <code class="literal">pci.vendor_id</code> (int)
+              </td><td>example: 0x1002</td><td>Yes</td><td>Vendor ID</td></tr><tr><td>
+                <code class="literal">pci.subsys_product_id</code> (int)
+              </td><td>example: 0x009e</td><td>Yes</td><td>Subsystem product id</td></tr><tr><td>
+                <code class="literal">pci.subsys_vendor_id</code> (int)
+              </td><td>example: 0x1028</td><td>Yes</td><td>Subsystem vendor id</td></tr><tr><td>
+                <code class="literal">pci.linux.sysfs_path</code> (string)
+              </td><td>example: /sys/devices/pci0000:00/0000:00:01/0000:01:00.0</td><td>Yes (only on Linux)</td><td>
+                Equals <code class="literal">linux.sysfs_path</code>
+              </td></tr><tr><td>
+                <code class="literal">pci.product</code> (string)
+              </td><td>Rage Mobility P/M AGP 2x</td><td>No</td><td>Name of the product per the PCI database</td></tr><tr><td>
+                <code class="literal">pci.vendor</code> (string)
+              </td><td>ATI Technologies Inc</td><td>No</td><td>Name of the vendor per the PCI database</td></tr><tr><td>
+                <code class="literal">pci.subsys_product</code> (string)
+              </td><td>Inspiron 7500</td><td>No</td><td>Name of the subsystem product per the PCI database</td></tr><tr><td>
+                <code class="literal">pci.subsys_vendor</code> (string)
+              </td><td>Dell Computer Corporation</td><td>No</td><td>Name of the subsystem vendor per the PCI database</td></tr></tbody></table></div><p>
+        (FIXME: Some key PCI information (bus, slot, port, function
+        etc.) is missing here)
+      </p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-serialif"></a>
+        serial namespace
+      </h3></div></div></div><p>
+        Device objects that represent serial devices (e.g. /dev/ttyS* or
+        /dev/ttyUSB*).
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">serial.originating_device</code> (string)
+              </td><td>
+                example: <code class="literal">/org/freedesktop/Hal/devices/pnp_PNP0501</code>
+              </td><td>Yes</td><td>UDI of the device the serial device is bound to.</td></tr><tr><td>
+                <code class="literal">serial.device</code> (string)
+              </td><td>example: /dev/ttyS0</td><td>Yes</td><td>The device node to access the OSS device.</td></tr><tr><td>
+                <code class="literal">serial.port</code> (int)
+              </td><td>example: 0</td><td>Yes</td><td>
+                The port number of the device, based on the number in
+                <code class="literal">serial.device</code>
+              </td></tr><tr><td>
+                <code class="literal">serial.type</code> (string)
+              </td><td>example: platform, usb, unknown</td><td>Yes</td><td>This property defines the type of the serial device.</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-usb"></a>
+        usb_device namespace
+      </h3></div></div></div><p>
+        For device objects representing USB devices the property
+        <code class="literal">info.subsystem</code> will be <code class="literal">usb_device</code>,
+        and the following properties will be available. Note that the
+        corresponding USB interfaces are represented by separate
+        device objects as children.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">usb_device.bus_number</code> (int)
+              </td><td>example: 1</td><td>Yes</td><td>The USB bus the device is attached to</td></tr><tr><td>
+                <code class="literal">usb_device.configuration_value</code> (int)
+              </td><td>example: 1</td><td>Yes</td><td>The current configuration the USB device is in;
+                starting from 1
+              </td></tr><tr><td>
+                <code class="literal">usb_device.configuration</code> (int)
+              </td><td>example: Bulk transfer configuration</td><td>No</td><td>Human-readable description of the current configuration the USB device is in
+              </td></tr><tr><td>
+                <code class="literal">usb_device.num_configurations</code> (int)
+              </td><td>example: 1</td><td>Yes</td><td>Number of configurations this USB device
+                can assume
+              </td></tr><tr><td>
+                <code class="literal">usb_device.device_class</code> (int)
+              </td><td>example: 0</td><td>Yes</td><td>USB Device Class</td></tr><tr><td>
+                <code class="literal">usb_device.device_subclass</code> (int)
+              </td><td>example: 0</td><td>Yes</td><td>USB Device Sub Class</td></tr><tr><td>
+                <code class="literal">usb_device.device_protocol</code> (int)
+              </td><td>example: 0</td><td>Yes</td><td>USB Device Protocol</td></tr><tr><td>
+                <code class="literal">usb_device.is_self_powered</code> (bool)
+              </td><td>example: false</td><td>Yes</td><td>The device, in the current configuration, is self
+                powered
+              </td></tr><tr><td>
+                <code class="literal">usb_device.can_wake_up</code> (bool)
+              </td><td>example: true</td><td>Yes</td><td>The device, in the current configuration, can wake up</td></tr><tr><td>
+                <code class="literal">usb_device.max_power</code> (int)
+              </td><td>example: 98</td><td>Yes</td><td>Max power drain of device, in mA</td></tr><tr><td>
+                <code class="literal">usb_device.num_interfaces</code> (int)
+              </td><td>example: 1</td><td>Yes</td><td>Number of USB Interfaces in the current configuration</td></tr><tr><td>
+                <code class="literal">usb_device.num_ports</code> (int)
+              </td><td>example: 0</td><td>Yes</td><td>Number of ports on a hub. Zero for non-hubs</td></tr><tr><td>
+                <code class="literal">usb_device.port_number</code> (int)
+              </td><td>example: 1</td><td>Yes</td><td>The port number on the parent hub that the device is attached to, starting from 1</td></tr><tr><td>
+                <code class="literal">usb_device.speed</code> (double)
+              </td><td>examples: 1.5, 12.0, 480.0</td><td>Yes</td><td>Speed of device, in Mbit/s</td></tr><tr><td>
+                <code class="literal">usb_device.version</code> (double)
+              </td><td>examples: 1.0, 1.1, 2.0</td><td>Yes</td><td>USB version of device</td></tr><tr><td>
+                <code class="literal">usb_device.level_number</code> (int)
+              </td><td>example: 2</td><td>Yes</td><td>Depth in USB tree, where the virtual root hub
+                is at depth 0
+              </td></tr><tr><td>
+                <code class="literal">usb_device.linux.device_number</code> (string)
+              </td><td>example: 19</td><td>Yes (only on Linux)</td><td>USB Device Number as assigned by the Linux kernel</td></tr><tr><td>
+                <code class="literal">usb_device.linux.parent_number</code> (string)
+              </td><td>example: 19</td><td>Yes (only on Linux)</td><td>Device number of parent device as assigned by the
+                Linux kernel
+              </td></tr><tr><td>
+                <code class="literal">usb_device.linux.sysfs_path</code> (string)
+              </td><td>example: /sys/devices/pci0000:00/0000:00:07.2/usb1/1-1/1-1.1</td><td>Yes (only on Linux)</td><td>
+                Equals <code class="literal">linux.sysfs_path</code>
+              </td></tr><tr><td>
+                <code class="literal">usb_device.product_id</code> (int)
+              </td><td>example: 0x3005</td><td>Yes</td><td>USB Product ID</td></tr><tr><td>
+                <code class="literal">usb_device.vendor_id</code> (int)
+              </td><td>example: 0x04b3</td><td>Yes</td><td>USB Vendor ID</td></tr><tr><td>
+                <code class="literal">usb_device.device_revision_bcd</code> (int)
+              </td><td>example: 0x0100</td><td>Yes</td><td>Device Revision Number encoded in BCD with two decimals</td></tr><tr><td>
+                <code class="literal">usb_device.serial</code> (string)
+              </td><td> </td><td>No</td><td>A string uniquely identifying the instance
+                of the device; ie. it will be different for two devices
+                of the same type. Note that the serial number is broken
+                on some USB devices.
+              </td></tr><tr><td>
+                <code class="literal">usb_device.product</code> (string)
+              </td><td>example: IBM USB HUB KEYBOARD</td><td>No</td><td>Name of the product per the USB ID Database</td></tr><tr><td>
+                <code class="literal">usb_device.vendor</code> (string)
+              </td><td>example: IBM Corp.</td><td>No</td><td>Name of the vendor per the USB ID Database</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-usbif"></a>
+        usb namespace
+      </h3></div></div></div><p>
+        Device objects that represent USB interfaces, ie. when
+        <code class="literal">info.subsystem</code> assumes <code class="literal">usb</code>,
+        are represented by the properties below. In addition all
+        the <code class="literal">usb_device.*</code> properties from the parent
+        USB device is available in this namespace but only with
+        the <code class="literal">usb</code> prefix instead of
+        <code class="literal">usb_device</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">usb.interface.class</code> (int)
+              </td><td>example: 0x03</td><td>Yes</td><td>USB Class for the interface</td></tr><tr><td>
+                <code class="literal">usb.interface.subclass</code> (int)
+              </td><td>example: 0x01</td><td>Yes</td><td>USB Sub Class for this interface</td></tr><tr><td>
+                <code class="literal">usb.interface.protocol</code> (int)
+              </td><td>example: 0x01</td><td>Yes</td><td>USB Protocol for the interface</td></tr><tr><td>
+                <code class="literal">usb.interface.description</code> (int)
+              </td><td>example: SyncML interface</td><td>No</td><td>Human-readable description for the interface provided by the device</td></tr><tr><td>
+                <code class="literal">usb.interface.number</code> (int)
+              </td><td>example: 1</td><td>Yes</td><td>Number of this interface, starting from zero</td></tr><tr><td>
+                <code class="literal">usb.linux.sysfs_path</code> (string)
+              </td><td>example: /sys/devices/pci0000:00/0000:00:07.2/usb1/1-1/1-1.1/1-1.1:1.0</td><td>Yes (only on Linux)</td><td>
+                Equals <code class="literal">linux.sysfs_path</code>
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-platform"></a>
+        platform namespace
+      </h3></div></div></div><p>
+        Devices that are built into the platform or present on busses that
+        cannot be properly enumerated (e.g. ISA) are represented by device
+        objects where <code class="literal">info.subsystem</code> equals
+        <code class="literal">platform</code>. These kind of devices are commonly,
+        somewhat incorrectly, called legacy devices.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">platform.id</code> (string)
+              </td><td>example: serial</td><td>Yes</td><td>Device identification</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-ide-host"></a>
+        ide_host namespace
+      </h3></div></div></div><p>
+        The <code class="literal">ide_host</code> namespace is present for
+        device objects where <code class="literal">info.subsystem</code> is set
+        to <code class="literal">ide_host</code>.  Such device objects represent
+        IDE and ATA host adaptors for harddisks and optical drives as
+        found in the majority of computer systems.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ide_host.number</code> (int)
+              </td><td> </td><td>Yes</td><td>A unique number identifying the IDE host adaptor</td></tr><tr><td>
+                <code class="literal">ide_host.linux.sysfs_path</code> (string)
+              </td><td>example: /sys/devices/pci0000:00/0000:00:07.1/ide0</td><td>Yes (only on Linux)</td><td>
+                Equals <code class="literal">linux.sysfs_path</code>
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-ide"></a>
+        ide namespace
+      </h3></div></div></div><p>
+        ATA and IDE drives are represented by device objects where
+        <code class="literal">info.subsystem</code> equals <code class="literal">ide</code>. The
+        following properties are available for such device objects.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ide.host</code> (int)
+              </td><td> </td><td>Yes</td><td>Corresponds
+                to <code class="literal">ide_host.host_number</code> of
+                the <code class="literal">ide_host</code> device that is the
+                parent of this device object
+              </td></tr><tr><td>
+                <code class="literal">ide.channel</code> (int)
+              </td><td> </td><td>Yes</td><td>Identifies the IDE channel of the host interface</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-scsi_host"></a>
+        scsi_host namespace
+      </h3></div></div></div><p>
+        The <code class="literal">scsi_host</code> namespace is present for
+        device objects where <code class="literal">info.subsystem</code> is set
+        to <code class="literal">scsi_host</code>.  Such device objects represent
+        SCSI host adaptors for SCSI devices as found in some computer
+        systems.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">scsi_host.host</code> (int)
+              </td><td> </td><td>Yes</td><td>A unique number identifying the SCSI host adaptor</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-scsi"></a>
+        scsi namespace
+      </h3></div></div></div><p>
+        SCSI devices are represented by device objects where
+        <code class="literal">info.subsystem</code> equals <code class="literal">scsi</code>.
+        The following properties are available for such device objects.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">scsi.host</code> (int)
+              </td><td> </td><td>Yes</td><td>
+                Corresponds to <code class="literal">scsi_host.host</code>
+                of the <code class="literal">scsi_host</code> device that is the
+                parent of this device object
+              </td></tr><tr><td>
+                <code class="literal">scsi.bus</code> (int)
+              </td><td> </td><td>Yes</td><td>SCSI channel number</td></tr><tr><td>
+                <code class="literal">scsi.target</code> (int)
+              </td><td> </td><td>Yes</td><td>SCSI identifier number</td></tr><tr><td>
+                <code class="literal">scsi.lun</code> (int)
+              </td><td> </td><td>Yes</td><td>SCSI Logical Unit Number</td></tr><tr><td>
+                <code class="literal">scsi.type</code> (string)
+              </td><td>Example: disk</td><td>Yes</td><td>SCSI device type</td></tr><tr><td> </td><td>cdrom</td><td> </td><td>This is a SCSI cdrom device.</td></tr><tr><td> </td><td>comm</td><td> </td><td>This is a SCSI communication device.</td></tr><tr><td> </td><td>disk</td><td> </td><td>This is a SCSI disk device.</td></tr><tr><td> </td><td>medium_changer</td><td> </td><td>This is a SCSI media changer (e.g. for CD/Tape).</td></tr><tr><td> </td><td>printer</td><td> </td><td>This is a SCSI printer.</td></tr><tr><td> </td><td>processor</td><td> </td><td>This is a SCSI processor device.</td></tr><tr><td> </td><td>raid</td><td> </td><td>This is a SCSI raid device.</td></tr><tr><td> </td><td>scanner</td><td> </td><td>This is a SCSI scanner.</td></tr><tr><td> </td><td>tape</td><td> </td><td>This is a SCSI tape device.</td></tr><tr><td> </td><td>unknown</td><td> </td><td>The type of this SCSI device is unknwon.</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-ieee1394_host"></a>
+        ieee1394_host namespace
+      </h3></div></div></div><p>
+        Device objects with <code class="literal">info.subsystem</code> set to
+        <code class="literal">ieee1394_host</code> represent IEEE 1394 host
+        adaptors. The following properties are available for such
+        device objects.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ieee1394_host.is_busmgr</code> (bool)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr><tr><td>
+                <code class="literal">ieee1394_host.is_irn</code> (bool)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr><tr><td>
+                <code class="literal">ieee1394_host.is_root</code> (bool)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr><tr><td>
+                <code class="literal">ieee1394_host.node_count</code> (int)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr><tr><td>
+                <code class="literal">ieee1394_host.nodes_active</code> (int)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-ieee1394_node"></a>
+        ieee1394_node namespace
+      </h3></div></div></div><p>
+        Device objects with <code class="literal">info.subsystem</code> set to
+        <code class="literal">ieee1394_node</code> represent IEEE 1394 nodes on
+        a IEEE 1394 bus. The following properties are available for
+        such device objects.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ieee1394_node.capabilities</code> (int)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr><tr><td>
+                <code class="literal">ieee1394_node.guid</code> (int)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr><tr><td>
+                <code class="literal">ieee1394_node.nodeid</code> (int)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr><tr><td>
+                <code class="literal">ieee1394_node.vendor</code> (int)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr><tr><td>
+                <code class="literal">ieee1394_node.vendor_id</code> (int)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-ieee1394"></a>
+        ieee1394 namespace
+      </h3></div></div></div><p>
+        Device objects with <code class="literal">info.subsystem</code> set to
+        <code class="literal">ieee1394</code> represent IEEE 1394 devices. The
+        following properties are available for such device objects.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ieee1394.specifier_id</code> (int)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-mmc_host"></a>
+        mmc_host namespace
+      </h3></div></div></div><p>
+        Device objects with <code class="literal">info.subsystem</code> set to
+        <code class="literal">mmc_host</code> represent MultiMediaCard or
+        Secure Digital host adaptors. The following properties
+        are available for such device objects.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">mmc_host.host</code> (int)
+              </td><td> </td><td>Yes</td><td>A unique number identifying the MMC/SD host adaptor</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-mmc"></a>
+        mmc namespace
+      </h3></div></div></div><p>
+        Device objects with <code class="literal">info.subsystem</code> set to
+        <code class="literal">mmc</code> represent MultiMediaCard or Secure
+        Digital cards. The following properties are available for
+        such device objects.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">mmc.cid</code> (string)
+              </td><td>example: 0150415330303842413a1a8083003a9d</td><td>Yes</td><td>Card Identification Data register (unique for every card
+                in existence)
+              </td></tr><tr><td>
+                <code class="literal">mmc.csd</code> (string)
+              </td><td>example: 005d013213598067b6d9cfff1640002d</td><td>Yes</td><td>Card Specific Data register</td></tr><tr><td>
+                <code class="literal">mmc.scr</code> (string)
+              </td><td>example: 00a5000000410000</td><td>Only for SD cards</td><td>SD Card Register</td></tr><tr><td>
+                <code class="literal">mmc.rca</code> (int)
+              </td><td>example: 8083</td><td>Yes</td><td>Card bus address</td></tr><tr><td>
+                <code class="literal">mmc.oem</code> (string)
+              </td><td> </td><td>Yes</td><td>Card OEM distributor</td></tr><tr><td>
+                <code class="literal">mmc.date</code> (string)
+              </td><td>example: 10/2003</td><td>Yes</td><td>Manufacturing date</td></tr><tr><td>
+                <code class="literal">mmc.serial</code> (int)
+              </td><td>example: 0x3a1a8083</td><td>Yes</td><td>Card serial number</td></tr><tr><td>
+                <code class="literal">mmc.hwrev</code> (int)
+              </td><td>example: 4</td><td>Yes</td><td>Hardware revision</td></tr><tr><td>
+                <code class="literal">mmc.fwrev</code> (int)
+              </td><td>example: 1</td><td>Yes</td><td>Firmware revision</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-ccw"></a>
+        ccw namespace
+      </h3></div></div></div><p>
+        Device objects that represent s390 ccw devices (when <code class="literal">info.subsystem
+        </code>
+         is set to <code class="literal">ccw</code>) are represented by the
+        properties below.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ccw.devtype</code> (string)
+              </td><td>example: 1732/01</td><td>Yes</td><td>Device type/model or n/a</td></tr><tr><td>
+                <code class="literal">ccw.cutype</code> (string)
+              </td><td>example: 1731/01</td><td>Yes</td><td>Control unit type/model</td></tr><tr><td>
+                <code class="literal">ccw.cmb_enable</code> (int)
+              </td><td>example: 1</td><td>Yes</td><td>If channel measurements are enabled</td></tr><tr><td>
+                <code class="literal">ccw.availability</code> (string)
+              </td><td>example: good</td><td>Yes</td><td>Can be one of 'good', 'boxed', 'no path',
+                or 'no device'
+              </td></tr><tr><td>
+                <code class="literal">ccw.online</code> (int)
+              </td><td>example: 1</td><td>Yes</td><td>Online status</td></tr><tr><td>
+                <code class="literal">ccw.bus_id</code> (string)
+              </td><td>example: 0.0.f588</td><td>Yes</td><td>The device's bus id in sysfs</td></tr><tr><td>
+                <code class="literal">ccw.subchannel.pim</code> (int)
+              </td><td>example: 0x80</td><td>No</td><td>path installed mask</td></tr><tr><td>
+                <code class="literal">ccw.subchannel.pam</code> (int)
+              </td><td>example: 0x80</td><td>No</td><td>path available mask</td></tr><tr><td>
+                <code class="literal">ccw.subchannel.pom</code> (int)
+              </td><td>example: 0xff</td><td>No</td><td>path operational mask</td></tr><tr><td>
+                <code class="literal">ccw.subchannel.chpid0..7</code> (int)
+              </td><td>example: 0x40</td><td>No</td><td>channel path ids</td></tr></tbody></table></div><p>
+        The following properties describe <code class="literal">ccw</code> devices where
+        <code class="literal">linux.driver</code> is either <code class="literal">dasd-eckd</code>
+        or <code class="literal">dasd-fba</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ccw.dasd.use_diag</code> (int)
+              </td><td>example: 0</td><td>Yes</td><td>If the device driver shall use diagnose calls to access
+                the device
+              </td></tr><tr><td>
+                <code class="literal">ccw.dasd.readonly</code> (int)
+              </td><td>example: 0</td><td>Yes</td><td>If the device can only be accessed readonly</td></tr><tr><td>
+                <code class="literal">ccw.dasd.discipline</code> (string)
+              </td><td>example: ECKD</td><td>No</td><td>The dasd discipline used to access the device</td></tr></tbody></table></div><p>
+        The following properties describe <code class="literal">ccw</code> devices where
+        <code class="literal">linux.driver</code> is <code class="literal">zfcp</code>. They are
+        only present when <code class="literal">ccw.online = 1</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ccw.zfcp.in_recovery</code> (int)
+              </td><td>example: 0</td><td>Yes</td><td>Shows whether the adapter is currently in recovery</td></tr><tr><td>
+                <code class="literal">ccw.zfcp.failed</code> (int)
+              </td><td>example: 0</td><td>Yes</td><td>Shows whether the adapter is in failed state</td></tr></tbody></table></div><p>
+        The following properties describe <code class="literal">ccw</code> devices where
+        <code class="literal">linux.driver</code> is of the form <code class="literal">tape_3xxx
+        </code>
+        .
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ccw.tape.state</code> (string)
+              </td><td>example: IN_USE</td><td>Yes</td><td>The current status of the tape</td></tr><tr><td>
+                <code class="literal">ccw.tape.operation</code> (string)
+              </td><td>example: REW</td><td>Yes</td><td>A three-letter mnemonic of the current tape operation
+              </td></tr><tr><td>
+                <code class="literal">ccw.tape.medium_state</code> (string)
+              </td><td>example: no medium</td><td>No</td><td>
+                If <code class="literal">ccw.online = 1</code>, shows whether a tape
+                is loaded
+              </td></tr><tr><td>
+                <code class="literal">ccw.tape.blocksize</code> (int)
+              </td><td>example: 512</td><td>No</td><td>
+                If <code class="literal">ccw.online = 1</code>, shows the blocksize
+                used for reads and writes to the tape
+              </td></tr></tbody></table></div><p>
+        The following properties describe <code class="literal">ccw</code> devices where
+        <code class="literal">linux.driver</code> is <code class="literal">3270</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ccw.3270.model</code> (int)
+              </td><td>example: 3</td><td>Yes</td><td>The model of the device, determining rows and columns
+              </td></tr><tr><td>
+                <code class="literal">ccw.3270.rows</code> (int)
+              </td><td>example: 32</td><td>Yes</td><td>The number of rows</td></tr><tr><td>
+                <code class="literal">ccw.3270.columns</code> (int)
+              </td><td>example: 80</td><td>Yes</td><td>The number of columns</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-ccwgroup"></a>
+        ccwgroup namespace
+      </h3></div></div></div><p>
+        Device objects that represent groups of <code class="literal">ccw</code> devices
+        (when <code class="literal">info.subsystem</code> is set to <code class="literal">ccwgroup</code>
+        have the properties specified below.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ccwgroup.online</code> (int)
+              </td><td>example: 1</td><td>Yes</td><td>Online status</td></tr><tr><td>
+                <code class="literal">ccwgroup.bus_id</code> (string)
+              </td><td>example: 0.0.f588</td><td>Yes</td><td>The device's bus id in sysfs</td></tr></tbody></table></div><p>
+        The following properties describe <code class="literal">ccwgroup</code> devices
+        where <code class="literal">linux.driver</code> is <code class="literal">qeth</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ccwgroup.qeth.large_send</code> (string)
+              </td><td>example: TSO</td><td>No</td><td>Whether large send is provided. Can be "no", "EDDP"
+                (software) or "TSO" (hardware).
+              </td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.card_type</code> (string)
+              </td><td>example: OSD_1000</td><td>Yes</td><td>Type of the card</td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.checksumming</code> (string)
+              </td><td>example: sw checksumming</td><td>No</td><td>The method used to checksum incoming packets</td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.canonical_macaddr</code> (int)
+              </td><td>example: 0</td><td>No</td><td>Specifies the token ring macaddress format. Not valid in
+                layer2 mode and for ethernet devices.
+              </td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.broadcast_mode</code> (string)
+              </td><td>example: broadcast_allrings</td><td>No</td><td>The scope of token ring broadcasts. Not valid in layer2
+                mode and for ethernet devices.
+              </td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.fake_broadcast</code> (int)
+              </td><td>example: 0</td><td>No</td><td>Whether to fake broadcast capability. Not valid in layer2
+                mode.
+              </td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.fake_ll</code> (int)
+              </td><td>example: 0</td><td>No</td><td>Whether to add a faked link level header to packets.
+                Not valid in layer2 mode.
+              </td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.layer2</code> (int)
+              </td><td>example: 0</td><td>No</td><td>Whether the card operates in layer 2 mode</td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.portname</code> (string)
+              </td><td>example: OSAPORT</td><td>No</td><td>The port name which has been specified for the card</td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.portno</code> (int)
+              </td><td>example: 0</td><td>No</td><td>The relative port number on the card</td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.buffer_count</code> (int)
+              </td><td>example: 16</td><td>Yes</td><td>Number of inbound buffers used</td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.add_hhlen</code> (int)
+              </td><td>example: 0</td><td>No</td><td>How much additional space is provided in the hardware
+                header in skbs in front of packets
+              </td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.priority_queueing</code>
+                (string)
+              </td><td>example: always queue 2</td><td>No</td><td>Which priority queueing algorithm is to be used</td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.route4</code> (string)
+              </td><td>example: no</td><td>No</td><td>Whether the card has a routing functionality for ipv4.
+                Not valid in layer2 mode.
+              </td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.route6</code> (string)
+              </td><td>example: no</td><td>No</td><td>Whether the card has a routing functionality for ipv6.
+                Not valid in layer2 mode.
+              </td></tr><tr><td>
+                <code class="literal">ccwgroup.qeth.state</code> (string)
+              </td><td>example: UP (LAN ONLINE)</td><td>Yes</td><td>The device's current state</td></tr></tbody></table></div><p>
+        The following properties describe <code class="literal">ccwgroup</code> devices
+        where <code class="literal">linux.driver</code> is <code class="literal">ctc</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ccwgroup.ctc.protocol</code> (int)
+              </td><td>example: 0</td><td>Yes</td><td>The protocol/method used by the connection</td></tr><tr><td>
+                <code class="literal">ccwgroup.ctc.type</code> (string)
+              </td><td>example: CTC/A</td><td>Yes</td><td>The device/connection type</td></tr><tr><td>
+                <code class="literal">ccwgroup.ctc.buffer</code> (int)
+              </td><td>example: 32768</td><td>No</td><td>The maximum buffer size of the connection</td></tr></tbody></table></div><p>
+        The following properties describe <code class="literal">ccwgroup</code> devices
+        where <code class="literal">linux.driver</code> is <code class="literal">lcs</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ccwgroup.lcs.portnumber</code> (int)
+              </td><td>example: 0</td><td>Yes</td><td>The port on the card that is used</td></tr><tr><td>
+                <code class="literal">ccwgroup.lcs.type</code> (string)
+              </td><td>example: OSA LCS card</td><td>Yes</td><td>The type of the card</td></tr><tr><td>
+                <code class="literal">ccwgroup.lcs.lancmd_timeout</code> (int)
+              </td><td>example: 5</td><td>Yes</td><td>The timeout value for LAN commands in seconds</td></tr></tbody></table></div><p>
+        The following properties describe <code class="literal">ccwgroup</code> devices
+        where <code class="literal">linux.driver</code> is <code class="literal">claw</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ccwgroup.claw.api_type</code> (string)
+              </td><td> </td><td>Yes</td><td>Determines the packing algorithm for outgoing pakets
+                (matching the remote peer)
+              </td></tr><tr><td> </td><td>IP</td><td> </td><td>Using the IP protocol</td></tr><tr><td> </td><td>PACKED</td><td> </td><td>Using an enhanced packing algorithm</td></tr><tr><td> </td><td>TCPIP</td><td> </td><td>Using the TCP/IP protocol</td></tr><tr><td>
+                <code class="literal">ccwgroup.claw.adapter_name</code> (string)
+              </td><td>example: RS1</td><td>Yes</td><td>The host name of the remote communication peer.</td></tr><tr><td>
+                <code class="literal">ccwgroup.claw.host_name</code> (string)
+              </td><td>example: LNX1</td><td>Yes</td><td>The host name of the local adapter.</td></tr><tr><td>
+                <code class="literal">ccwgroup.claw.read_buffer</code> (int)
+              </td><td>example: 4</td><td>Yes</td><td>The number of read buffers allocated</td></tr><tr><td>
+                <code class="literal">ccwgroup.claw.write_buffer</code> (int)
+              </td><td>example: 5</td><td>Yes</td><td>The number of write buffers allocated</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-iucv"></a>
+        iucv namespace
+      </h3></div></div></div><p>
+        Device objects with <code class="literal">info.subsystem</code> set to <code class="literal">iucv
+        </code>
+         are using the "Intra-User Comminication Vehicle" and are
+        described by the following properties.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">iucv.bus_id</code> (string)
+              </td><td>example: netiucv0</td><td>Yes</td><td>The device's bus id in sysfs</td></tr></tbody></table></div><p>
+        The following properties describe <code class="literal">iucv</code> devices
+        where <code class="literal">linux.driver</code> is <code class="literal">netiucv</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">iucv.netiucv.user</code> (string)
+              </td><td>example: linux12</td><td>Yes</td><td>The guest name of the connection's target</td></tr><tr><td>
+                <code class="literal">iucv.netiucv.buffer</code> (int)
+              </td><td>example: 32768</td><td>Yes</td><td>The maximum buffer size of the connection</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-block"></a>
+        block namespace
+      </h3></div></div></div><p>
+        Device objects representing addressable block devices, such as
+        drives and partitions, will have <code class="literal">info.subsystem</code>
+        set to <code class="literal">block</code> and will export a number of
+        properties in the <code class="literal">block</code> namespace.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">block.device</code> (string)
+              </td><td>example: /dev/sda </td><td>Yes</td><td>Special device file to interact with the block device</td></tr><tr><td>
+                <code class="literal">block.major</code> (int)
+              </td><td>example: 8</td><td>Yes</td><td>Major number of special file to interact with the
+                device
+              </td></tr><tr><td>
+                <code class="literal">block.minor</code> (int)
+              </td><td>example: 1</td><td>Yes</td><td>Minor number of special file to interact with the
+                device
+              </td></tr><tr><td>
+                <code class="literal">block.is_volume</code> (bool)
+              </td><td> </td><td>Yes</td><td>True only when the block device is a volume that can
+                be mounted into the file system. In this case the
+                <code class="literal">volume</code> capability will be set and
+                thus, properties, in the <code class="literal">volume</code>
+                namespace are available.
+              </td></tr><tr><td>
+                <code class="literal">block.no_partitions</code> (bool)
+              </td><td> </td><td>Yes</td><td>For toplevel block devices, this is TRUE only
+                when no known partition tables have been found on the
+                media (In this case, if the storage device contain a
+                file system it will be accessible using the same
+                special device file as the one for this device object
+                and the device object representing the filesystem will
+                appear as a separate device object as a child). For
+                the child, that is
+                when <code class="literal">block.is_volume</code> is true, this
+                property is TRUE exactly when it was created for a
+                storage device with
+                the <code class="literal">storage.no_partitions_hint</code> set
+                to TRUE.
+              </td></tr><tr><td>
+                <code class="literal">block.have_scanned</code> (bool)
+              </td><td> </td><td>Yes</td><td>
+                An internal property used by HAL to specify whether a top
+                level block device have already been scanned for filesystems.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-xen"></a>xen namespace</h3></div></div></div><p>
+       Device objects representing virtual devices under the Xen
+       Virtual Machine Monitor, such as frontend network or block
+       devices, will have <code class="literal">info.subsystem</code> set to
+       <code class="literal">block</code> and will export a number of
+       properties in then <code class="literal">xen</code> namespace.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code class="literal">xen.bus_id</code> (string)</td><td>example: vif-0 </td><td>Yes</td><td>The XenBus ID of the device</td></tr><tr><td><code class="literal">xen.path</code> (string)</td><td>example: device/vif/0 </td><td>Yes</td><td>The XenBus path of the device</td></tr><tr><td><code class="literal">xen.type</code> (string)</td><td>example: vif</td><td>Yes</td><td>The type of Xen device</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-bluetooth_hci"></a>bluetooth_hci namespace</h3></div></div></div><p>
+       Device objects representing a Bluetooth Host Controller Interface.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code class="literal">bluetooth_hci.address</code> (uint64)</td><td> </td><td>Yes</td><td>Address of the host controller interface.</td></tr><tr><td><code class="literal">bluetooth_hci.originating_device</code> (string)</td><td> </td><td>Yes</td><td>The UDI of the physical device (e.g. an USB interface) that provides the HCI hardware.</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-bluetooth_acl"></a>bluetooth_acl namespace</h3></div></div></div><p>
+       Device objects representing Asynchronous Connection-oriented Links.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code class="literal">bluetooth_acl.address</code> (uint64)</td><td> </td><td>Yes</td><td>Address of the device at the other end of the connection.</td></tr><tr><td><code class="literal">bluetooth_acl.originating_device</code> (string)</td><td> </td><td>Yes</td><td>The UDI of the Bluetooth HCI (of
+              capability <code class="literal">bluetooth_hci</code>) that the
+              connection is made through.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-bluetooth_sco"></a>bluetooth_sco namespace</h3></div></div></div><p>
+       Device objects representing Synchronous Connection-Oriented links.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code class="literal">bluetooth_sco.address</code> (uint64)</td><td> </td><td>Yes</td><td>Address of the device at the other end of the connection.</td></tr><tr><td><code class="literal">bluetooth_sco.originating_device</code> (string)</td><td> </td><td>Yes</td><td>The UDI of the Bluetooth HCI (of
+              capability <code class="literal">bluetooth_hci</code>) that the
+              connection is made through.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-drm"></a>drm namespace</h3></div></div></div><p>
+       The <code class="literal">drm</code> namespace is present for Direct Rendering Manager device objects.
+       They represent a Direct Rendering Interface.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code class="literal">drm.dri_library</code> (string)</td><td> </td><td>Yes</td><td>Name of the dri (Direct Rendering Interface) library (e.g. i915).</td></tr><tr><td><code class="literal">drm.version</code> (string)</td><td> </td><td>Yes</td><td>The drm version (of the kernel module/diver).</td></tr></tbody></table></div></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="properties-functional"></a>Functional Properties</h2></div></div></div><p>
+      The section describe functional properties of device objects,
+      that is, properties that are merged onto device objects
+      representing addressable hardware. In most
+      circumstances such properties stem from a kernel level
+      driver attached to the device represented by the device object,
+      however, as HAL can merge properties from anywhere, they
+      may have been merged from device information files or callouts.
+    </p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-kernel"></a>
+        system namespace
+      </h3></div></div></div><p>
+        This namespace is found on the toplevel "Computer" device,
+        and represents information about the system and the currently
+        running kernel.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">system.kernel.name</code> (string)
+              </td><td>example: Linux</td><td>No</td><td>
+                The name of the kernel, usually the equivalent of
+                <code class="literal">uname -s</code>.
+              </td></tr><tr><td>
+                <code class="literal">system.kernel.version</code> (string)
+              </td><td>example: 2.6.5-7.104-default</td><td>No</td><td>
+                The version of the currently running kernel.  Usually
+                the equivalent of <code class="literal">uname -r</code>.
+              </td></tr><tr><td>
+                <code class="literal">system.kernel.machine</code> (string)
+              </td><td>example: i686</td><td>No</td><td>
+                The "machine hardware name" of the currently running kernel.
+                Usually the equivalent of <code class="literal">uname -m</code>.
+              </td></tr><tr><td>
+                <code class="literal">system.formfactor</code> (string)
+              </td><td>example: laptop, desktop, server, unknown</td><td>Yes</td><td>
+                The formfactor of the system. Usually the equivalent of
+                <code class="literal">system.chassis.type</code> or set from information
+                about ACPI/APM/PMU properties.
+              </td></tr><tr><td>
+                <code class="literal">system.hardware.vendor</code> (string)
+              </td><td> </td><td>No</td><td>
+                The name of the manufacturer of the machine.
+              </td></tr><tr><td>
+                <code class="literal">system.product</code> (string)
+              </td><td> </td><td>No</td><td>
+                The product name of the machine.
+              </td></tr><tr><td>
+                <code class="literal">system.hardware.version</code> (string)
+              </td><td> </td><td>No</td><td>
+                The version of the machine.
+              </td></tr><tr><td>
+                <code class="literal">system.hardware.serial</code> (string)
+              </td><td> </td><td>No</td><td>
+                The serial number of the machine.
+              </td></tr><tr><td>
+                <code class="literal">system.hardware.uuid</code> (string)
+              </td><td> </td><td>No</td><td>
+                The unique ID of the machine.
+              </td></tr><tr><td>
+                <code class="literal">system.hardware.primary_video.vendor</code> (int)
+              </td><td> </td><td>No</td><td>
+                The PCI vendor ID of the primary graphics card in the system.
+              </td></tr><tr><td>
+                <code class="literal">system.hardware.primary_video.product</code> (int)
+              </td><td> </td><td>No</td><td>
+                The PCI device ID of the primary graphics card in the system.
+              </td></tr><tr><td>
+                <code class="literal">system.firmware.vendor</code> (string)
+              </td><td> </td><td>No</td><td>
+                The firmware vendor.
+              </td></tr><tr><td>
+                <code class="literal">system.firmware.version</code> (string)
+              </td><td> </td><td>No</td><td>
+                The firmware version.
+              </td></tr><tr><td>
+                <code class="literal">system.firmware.release_date</code> (string)
+              </td><td> </td><td>No</td><td>
+                The release date of the firmware.
+              </td></tr><tr><td>
+                <code class="literal">system.chassis.manufacturer</code> (string)
+              </td><td> </td><td>No</td><td>
+                The manufacturer of the chassis.
+              </td></tr><tr><td>
+                <code class="literal">system.chassis.type</code> (string)
+              </td><td> </td><td>No</td><td>
+                The chassis type of the machine.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-volume"></a>
+        volume namespace
+      </h3></div></div></div><p>
+        This namespace is for device objects that represent storage
+        devices with a filesystem that can be mounted. Such device
+        objects will have the capability <code class="literal">volume</code> and
+        they will export the properties below. Note that device
+        objects can only have the <code class="literal">volume</code> capability
+        if they already have the capability <code class="literal">block</code>
+        and the property <code class="literal">block.is_volume</code> set to TRUE.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">volume.ignore</code> (bool)
+              </td><td> </td><td>Yes</td><td>This is a hint to software higher in the stack
+                that this volume should be ignored. If TRUE, the volume
+                should be invisible in the UI and mount wrappers should
+                refuse to mount it on behalf on an unprivileged
+                user. This is useful for hiding e.g. firmware partitions
+                (e.g. bootstrap on Mac's) and OS reinstall partitions on
+                e.g. OEM systems.
+              </td></tr><tr><td>
+                <code class="literal">volume.is_mounted</code> (bool)
+              </td><td> </td><td>Yes</td><td>This property is TRUE if and only if the volume is mounted</td></tr><tr><td>
+                <code class="literal">volume.is_mounted_read_only</code> (bool)
+              </td><td> </td><td>Yes</td><td>This property is TRUE if and only if the volume is mounted and
+                the volume's file-system is read-only.
+              </td></tr><tr><td>
+                <code class="literal">volume.mount_point</code> (string)
+              </td><td>example: /media/compact_flash1  </td><td>Yes (is blank only when volume.is_mounted is FALSE)</td><td>A fully qualified path to the mount point of the volume</td></tr><tr><td>
+                <code class="literal">volume.fsusage</code> (string)
+              </td><td>example: filesystem</td><td>Yes</td><td>
+                This property specifies the expected usage of the volume
+              </td></tr><tr><td> </td><td>filesystem</td><td> </td><td>The volume is a mountable filesystem</td></tr><tr><td> </td><td>partitiontable</td><td> </td><td>
+               The volume contains a partitiontable.
+             </td></tr><tr><td> </td><td>raid</td><td> </td><td>The volume is a member of a raid set and not mountable</td></tr><tr><td> </td><td>other</td><td> </td><td>The volume is not mountable like a swap partition</td></tr><tr><td> </td><td>unused</td><td> </td><td>The volume is marked a unused or free</td></tr><tr><td>
+                <code class="literal">volume.fstype</code> (string)
+              </td><td>examples: ext3, vfat</td><td>Yes (is blank if the type is unknown)</td><td>The specific type of either the file system or what the volume is used for, cf. volume.fsusage</td></tr><tr><td>
+                <code class="literal">volume.fsversion</code> (string)
+              </td><td>example: FAT32</td><td> </td><td>Version number or subtype of the filesystem</td></tr><tr><td>
+                <code class="literal">volume.label</code> (string)
+              </td><td>example: 'Fedora Core 1.90' </td><td>Yes (is blank if no label is found)</td><td>The label of the volume</td></tr><tr><td>
+                <code class="literal">volume.uuid</code> (string)
+              </td><td>example: 4060-6C11</td><td>Yes (is blank if no UUID is found)</td><td>The Universal Unique Identifer for the volume</td></tr><tr><td>
+                <code class="literal">volume.is_disc</code> (bool)
+              </td><td> </td><td>Yes</td><td>If the volume stems from an optical disc, this
+                property is true and the device object will also have
+                the capability <code class="literal">volume.disc</code>
+              </td></tr><tr><td>
+                <code class="literal">volume.block_size</code> (string)
+              </td><td> </td><td>No</td><td>
+                The block size of the volume
+              </td></tr><tr><td>
+                <code class="literal">volume.num_blocks</code> (string)
+              </td><td> </td><td>No</td><td>
+                Number of blocks on the volume
+              </td></tr><tr><td>
+                <code class="literal">volume.size</code> (uint64)
+              </td><td> </td><td>No</td><td>
+                Size of the volume in bytes
+              </td></tr><tr><td>
+                <code class="literal">volume.is_partition</code> (bool)
+              </td><td> </td><td>Yes</td><td>
+                If the volume stems from a partition on e.g. a hard
+                disk, this property is set to <code class="literal">TRUE</code>.
+              </td></tr><tr><td>
+                <code class="literal">volume.linux.is_device_mapper</code> (bool)
+              </td><td> </td><td>Yes, but only on Linux</td><td>
+                If the volume stems from the Linux Device Mapper this property is set to <code class="literal">TRUE</code>.
+              </td></tr><tr><td>
+                <code class="literal">volume.partition.number</code> (int)
+              </td><td> </td><td>
+                If, and only if, <code class="literal">volume.is_partition</code>
+                is set to <code class="literal">TRUE</code>.
+              </td><td>
+                The number of the partition.
+              </td></tr><tr><td>
+                <code class="literal">volume.partition.label</code> (string)
+              </td><td> </td><td>
+                If, and only if, <code class="literal">volume.is_partition</code>
+                is set to <code class="literal">TRUE</code>.
+              </td><td>
+               Label of partition. Only available for "apm" and "gpt"
+               partition tables. Note that this is not the same as the
+               file system label defined in <code class="literal">volume.label</code>.
+              </td></tr><tr><td>
+                <code class="literal">volume.partition.uuid</code> (string)
+              </td><td> </td><td>
+                If, and only if, <code class="literal">volume.is_partition</code>
+                is set to <code class="literal">TRUE</code>.
+              </td><td>
+                The UUID or GUID of the partition table entry. Only available for
+               "gpt" partition tables.
+              </td></tr><tr><td>
+                <code class="literal">volume.partition.scheme</code> (string)
+              </td><td> </td><td>
+                If, and only if, <code class="literal">volume.is_partition</code>
+                is set to <code class="literal">TRUE</code>.
+              </td><td>
+                The scheme of the partition table this entry is part of.
+               Note that this is not necessarily the same as 
+               <code class="literal">storage.partitioning_scheme</code> as 
+               some partition tables can embed other partition tables.
+              </td></tr><tr><td> </td><td>mbr</td><td> </td><td>
+                Master Boot Record
+              </td></tr><tr><td> </td><td>embr</td><td> </td><td>
+                Extended Master Boot Record
+              </td></tr><tr><td> </td><td>gpt</td><td> </td><td>
+                GUID Partition Table as defined by EFI
+              </td></tr><tr><td> </td><td>apm</td><td> </td><td>
+                Apple Partition Map
+              </td></tr><tr><td>
+                <code class="literal">volume.partition.type</code> (string)
+              </td><td> </td><td>
+                If, and only if, <code class="literal">volume.is_partition</code>
+                is set to <code class="literal">TRUE</code>.
+              </td><td>
+                The type of the partition table entry. Depends on 
+               <code class="literal">volume.partition.scheme</code>.
+              </td></tr><tr><td> </td><td><code class="literal">mbr</code> and <code class="literal">embr</code> entries</td><td> </td><td>
+               The hexadecimal encoding of the 8-bit partition type, see 
+               http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
+               for a list. For example the Linux partition type is represented
+               as the string "0x83".
+              </td></tr><tr><td> </td><td><code class="literal">gpt</code> entries</td><td> </td><td>
+               The GUID encoded as a string. See http://en.wikipedia.org/wiki/GUID_Partition_Table
+               for a list of well-known GUID's.
+              </td></tr><tr><td> </td><td><code class="literal">apm</code> entries</td><td> </td><td>
+               Defined in http://developer.apple.com/documentation/mac/Devices/Devices-126.html.
+               Also note that for FAT file systems, it appears that "DOS_FAT_32", "DOS_FAT_16" 
+               and "DOS_FAT_12" are also recognized under Mac OS X (I've tested this too) cf. 
+               http://lists.apple.com/archives/Darwin-drivers/2003/May/msg00021.html
+              </td></tr><tr><td>
+                <code class="literal">volume.partition.flags</code> (strlist)
+              </td><td> </td><td>
+                If, and only if, <code class="literal">volume.is_partition</code>
+                is set to <code class="literal">TRUE</code>.
+              </td><td>
+               Flags conveying specific information about the partition
+               entry. Dependent on the partitioning scheme.
+              </td></tr><tr><td> </td><td><code class="literal">mbr</code> and <code class="literal">embr</code> entries</td><td> </td><td>
+               Only one flag, "boot", is defined. This is used by some BIOS'es and
+               boot loaders to populate a boot menu. It means that a partition is
+               bootable.
+              </td></tr><tr><td> </td><td><code class="literal">gpt</code> entries</td><td> </td><td>
+               Only the flag "required" is recognized. This corresponds to
+               bit 0 of the attibutes (at offset 48), meaning 
+               "Required for the platform to function. The system cannot 
+               function normally if this partition is removed. This
+               partition should be considered as part of the hardware of the
+               system, and if it is removed the system may not boot. It may
+               contain diagnostics, recovery tools, or other code or data that is
+               critical to the functioning of a system independent of any OS."
+              </td></tr><tr><td> </td><td><code class="literal">apm</code> entries</td><td> </td><td>
+               The following flags are recognized: 
+               "allocated" if the partition is already allocated; and
+               "in_use" if the partition is in use; may be cleared after a system reset; and
+               "boot" if partition contains valid boot information; and
+               "allow_read" if partition allows reading; and
+               "allow_write"; if partition allows writing; and
+               "boot_code_is_pic"; if boot code is position independent
+              </td></tr><tr><td>
+                <code class="literal">volume.partition.media_size</code> (uint64)
+              </td><td>example: 500107862016</td><td>
+                If, and only if, <code class="literal">volume.is_partition</code>
+                is set to <code class="literal">TRUE</code>.
+              </td><td>
+                If available, size of the current media or the fixed disk in the storage device.
+              </td></tr><tr><td>
+                <code class="literal">volume.partition.start</code> (uint64)
+              </td><td>example: 32256</td><td>
+                If, and only if, <code class="literal">volume.is_partition</code>
+                is set to <code class="literal">TRUE</code>.
+              </td><td>
+                If available, the offset where the partition starts on the media or the fixed disk in the storage device.
+              </td></tr></tbody></table></div><p>
+        Device objects with this capability may emit the following
+        device conditions
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Condition Name</th><th>Parameters</th><th>Example</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">VolumeMount</code>
+              </td><td>
+                <code class="literal">block.device</code> (string),
+                <code class="literal">volume.mount_point</code> (string)
+              </td><td>
+                <code class="literal">/dev/sda1</code>,
+                <code class="literal">/media/compact_flash</code>
+              </td><td>Emitted when a volume is mounted</td></tr><tr><td>
+                <code class="literal">VolumeUnmount</code>
+              </td><td>
+                <code class="literal">block.device</code> (string),
+                <code class="literal">volume.mount_point</code> (string)
+              </td><td>
+                <code class="literal">/dev/sda1</code>,
+                <code class="literal">/media/compact_flash</code>
+              </td><td>Emitted when a volume is unmounted</td></tr><tr><td>
+                <code class="literal">VolumeUnmountForced</code>
+              </td><td>
+                <code class="literal">block.device</code> (string),
+                <code class="literal">volume.mount_point</code> (string)
+              </td><td>
+                <code class="literal">/dev/sda1</code>,
+                <code class="literal">/media/compact_flash</code>
+              </td><td>
+                Emitted when a volume is forcibly unmounted because
+                the media backing the volume was removed.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-volume-disc"></a>
+        volume.disc namespace
+      </h3></div></div></div><p>
+        This namespace is for device objects that represent optical
+        discs, e.g. device objects with the capability
+        <code class="literal">volume.disc</code>. Such device objects will
+        also have the capability <code class="literal">volume</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">volume.disc.has_audio</code> (bool)
+              </td><td> </td><td>Yes</td><td>Is true only if the disc contains audio</td></tr><tr><td>
+                <code class="literal">volume.disc.has_data</code> (bool)
+              </td><td> </td><td>Yes</td><td>Is true only if the disc contains data</td></tr><tr><td>
+                <code class="literal">volume.disc.is_vcd</code> (bool)
+              </td><td> </td><td>Yes</td><td>Is true only if the disc is a Video CD</td></tr><tr><td>
+                <code class="literal">volume.disc.is_svcd</code> (bool)
+              </td><td> </td><td>Yes</td><td>Is true only if the disc is a Super Video CD</td></tr><tr><td>
+                <code class="literal">volume.disc.is_videodvd</code> (bool)
+              </td><td> </td><td>Yes</td><td>Is true only if the disc is a Video DVD</td></tr><tr><td>
+                <code class="literal">volume.disc.is_appendable</code> (bool)
+              </td><td> </td><td>Yes</td><td>Is true only if it's possible to write additional data</td></tr><tr><td>
+                <code class="literal">volume.disc.is_blank</code> (bool)
+              </td><td> </td><td>Yes</td><td>Is true only if the disc is blank</td></tr><tr><td>
+                <code class="literal">volume.disc.is_rewritable</code> (bool)
+              </td><td> </td><td>Yes</td><td>Is true only if the disc is rewritable</td></tr><tr><td>
+                <code class="literal">volume.disc.capacity</code> (uint64)
+              </td><td> </td><td>No</td><td>Capacity of disc, in bytes</td></tr><tr><td>
+                <code class="literal">volume.disc.type</code> (string)
+              </td><td> </td><td>Yes</td><td>This property specifies the physical type of the disc</td></tr><tr><td> </td><td>cd_rom</td><td> </td><td>CD-ROM disc</td></tr><tr><td> </td><td>cd_r</td><td> </td><td>CD-R disc</td></tr><tr><td> </td><td>cd_rw</td><td> </td><td>CD-RW disc</td></tr><tr><td> </td><td>dvd_rom</td><td> </td><td>DVD-ROM disc</td></tr><tr><td> </td><td>dvd_ram</td><td> </td><td>DVD-RAM disc</td></tr><tr><td> </td><td>dvd_r</td><td> </td><td>DVD-R disc</td></tr><tr><td> </td><td>dvd_rw</td><td> </td><td>DVD-RW disc</td></tr><tr><td> </td><td>dvd_plus_r</td><td> </td><td>DVD+R disc</td></tr><tr><td> </td><td>dvd_plus_rw</td><td> </td><td>DVD+RW disc</td></tr><tr><td> </td><td>bd_rom</td><td> </td><td>BD-ROM disc</td></tr><tr><td> </td><td>bd_r</td><td> </td><td>BD-R disc</td></tr><tr><td> </td><td>bd_re</td><td> </td><td>BD-RE disc</td></tr><tr><td> </td><td>hddvd_rom</td><td> </td><td>HD DVD-ROM disc</td></tr><tr><td> </td><td>hddvd_r</td><td> </td><td>HD DVD-R disc</td></tr><tr><td> </td><td>hddvd_rw</td><td> </td><td>HD DVD-Rewritable disc</td></tr><tr><td> </td><td>unknown</td><td> </td><td>Unknown type or lack of support from drive to determine the type</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-storage"></a>
+        storage namespace
+      </h3></div></div></div><p>
+        This namespace is used to describe storage devices
+        and their capabilities. Such device objects will have the
+        capability <code class="literal">storage</code> and
+        they will export the properties below. Note that device
+        objects can only have the <code class="literal">storage</code> capability
+        if they already got capability <code class="literal">block</code> and the
+        property <code class="literal">block.is_volume</code> set to FALSE.
+        One significant between the <code class="literal">storage</code> and
+        <code class="literal">block</code> namespace is that the properties
+        exported in the <code class="literal">storage</code> represents
+        constant vital product information, whereas the properties
+        in the <code class="literal">block</code> namespace represent
+        variable system-dependent information.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">storage.bus</code> (string)
+              </td><td> </td><td>Yes</td><td>Interface the storage device is attached to</td></tr><tr><td> </td><td>ide</td><td> </td><td>IDE or ATA interface</td></tr><tr><td> </td><td>usb</td><td> </td><td>USB interface</td></tr><tr><td> </td><td>ieee1394</td><td> </td><td>IEEE 1394 interface</td></tr><tr><td> </td><td>scsi</td><td> </td><td>SCSI interface</td></tr><tr><td> </td><td>sata</td><td> </td><td>SATA interface</td></tr><tr><td> </td><td>platform</td><td> </td><td>Legacy device that is part of the platform</td></tr><tr><td> </td><td>linux_raid</td><td> </td><td>Linux MD (multi disk) RAID device</td></tr><tr><td> </td><td> </td><td> </td><td> </td></tr><tr><td>
+                <code class="literal">storage.drive_type</code> (string)
+              </td><td> </td><td>Yes</td><td>
+                The type of the drive. Note that it may not be
+                possible to probe for some of these properties so in
+                some cases memory card readers may appear as
+                harddisks. Device information files can be used to
+                override this value.
+              </td></tr><tr><td> </td><td>disk</td><td> </td><td>The device is a harddisk</td></tr><tr><td> </td><td>cdrom</td><td> </td><td>
+                The device is an optical drive. The device object will also have the capability <code class="literal">storage.cdrom</code> in this case.
+              </td></tr><tr><td> </td><td>floppy</td><td> </td><td>The device is a floppy disk drive</td></tr><tr><td> </td><td>tape</td><td> </td><td>The device is a tape drive</td></tr><tr><td> </td><td>compact_flash</td><td> </td><td>The device is a card reader for Compact Flash memory cards</td></tr><tr><td> </td><td>memory_stick</td><td> </td><td>The device is a card reader for MemoryStick memory cards</td></tr><tr><td> </td><td>smart_media</td><td> </td><td>The device is a card reader for SmartMedia memory cards</td></tr><tr><td> </td><td>sd_mmc</td><td> </td><td>The device is a card reader for SecureDigital/MultiMediaCard memory cards</td></tr><tr><td> </td><td> </td><td> </td><td> </td></tr><tr><td>
+               <code class="literal">storage.removable</code> (bool)
+              </td><td> </td><td>Yes</td><td>Media can be removed from the storage device</td></tr><tr><td>
+               <code class="literal">storage.removable.media_available</code> (bool)
+              </td><td> </td><td>Yes</td><td>true, if and only if, media have been detected in storage device</td></tr><tr><td>
+               <code class="literal">storage.removable.media_size</code> (uint64)
+              </td><td> </td><td>Yes</td><td>Size of media in storage device. Available only if media have been detected in storage device.</td></tr><tr><td>
+               <code class="literal">storage.removable.support_async_notification</code> (bool)
+              </td><td> </td><td>Yes</td><td>Whether the drive reports asynchronous notification for media change.</td></tr><tr><td>
+               <code class="literal">storage.partitioning_scheme</code> (string)
+              </td><td> </td><td>Only when media is inserted and is partitioned</td><td>The partitioning scheme of the media.</td></tr><tr><td> </td><td>mbr</td><td> </td><td>Master Boot Record partitioning scheme used in most PC's</td></tr><tr><td> </td><td>gpt</td><td> </td><td>GUID Partitioning Table as defined by UEFI</td></tr><tr><td> </td><td>apm</td><td> </td><td>Apple Partition Map, used in non-Intel Apple computers</td></tr><tr><td>
+               <code class="literal">storage.size</code> (uint64)
+              </td><td> </td><td>No</td><td>size in bytes of the storage device - only meaningful if storage.removable is FALSE</td></tr><tr><td>
+                <code class="literal">storage.requires_eject</code> (bool)
+              </td><td> </td><td>Yes</td><td>The eject ioctl is required to properly eject the media</td></tr><tr><td>
+                <code class="literal">storage.hotpluggable</code> (bool)
+              </td><td> </td><td>Yes</td><td>The storage device can be removed while the system is running</td></tr><tr><td>
+                <code class="literal">storage.media_check_enabled</code> (bool)
+              </td><td> </td><td>Yes</td><td>If this property is set to FALSE then HAL will not continuosly poll for media changes. </td></tr><tr><td>
+                <code class="literal">storage.automount_enabled_hint</code> (bool)
+              </td><td> </td><td>Yes</td><td>This property is a hint to desktop file managers that they shouldn't automount volumes of the storage device when they appear.</td></tr><tr><td>
+                <code class="literal">storage.no_partitions_hint</code> (bool)
+              </td><td> </td><td>Yes</td><td>
+                This property is a hint to programs that maintain the
+                <code class="literal">/etc/fstab</code> file to signal, when
+                TRUE, that the storage drive (such as floppy or
+                optical drives) is used for media with no partition
+                table so an entry can be added ahead of media
+                insertion time. Note that this is only a hint; media
+                may be inserted that has partition tables that the
+                kernel may respect. Conversely, when this is FALSE
+                media without partition tables may be inserted (an
+                example is a Compact Flash card; this media is normally
+                formatted with a PC style partition table and a single
+                FAT partition. However, it may be formatted with just
+                a single FAT partition and no partition table).
+              </td></tr><tr><td>
+                <code class="literal">storage.originating_device</code> (string)
+              </td><td> </td><td>Yes</td><td>
+                This contains the UDI of the device object
+                representing the device or blank if
+                there is no such device.
+              </td></tr><tr><td>
+                <code class="literal">storage.model</code> (string)
+              </td><td> </td><td>Yes</td><td>The name of the drive</td></tr><tr><td>
+                <code class="literal">storage.vendor</code> (string)
+              </td><td> </td><td>Yes</td><td>The vendor of the drive</td></tr><tr><td>
+                <code class="literal">storage.serial</code> (string)
+              </td><td> </td><td>No</td><td>The serial number of the drive</td></tr><tr><td>
+                <code class="literal">storage.firmware_revision</code> (string)
+              </td><td> </td><td>No</td><td>The revision of the firmware of the drive</td></tr><tr><td>
+                <code class="literal">storage.icon.drive</code> (string)
+              </td><td> </td><td>No</td><td>
+                Name of icon to use for displaying the drive. The name
+                must comply with freedesktop.org icon-theme specification
+                and must not be an absolute path.
+                This property exists such that e.g. OEM's can install
+                icons in <code class="literal">/usr/share/icons/hicolor</code>
+                a device information file matching their device.
+              </td></tr><tr><td>
+                <code class="literal">storage.icon.volume</code> (string)
+              </td><td> </td><td>No</td><td>
+                Name of icon to use for displaying volumes from the drive.
+                The name must comply with freedesktop.org icon-theme
+                specification and must not be an absolute path.
+                This property exists such that e.g. OEM's can install
+                icons in <code class="literal">/usr/share/icons/hicolor</code>
+                a device information file matching their device.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-storage-cdrom"></a>
+        storage.cdrom namespace
+      </h3></div></div></div><p>
+        This namespace is used to describe optical storage drives
+        and their capabilities.Such device objects will have the
+        capability <code class="literal">storage.cdrom</code> and
+        they will export the properties below. Note that device
+        objects can only have the <code class="literal">storage.cdrom</code> capability
+        if they already got the capability <code class="literal">storage</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">storage.cdrom.cdr</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can write CD-R discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.cdrw</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can blank and write to CD-RW discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.dvd</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can read DVD-ROM discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.dvdr</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can write to DVD-R discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.dvdrw</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can blank and write to DVD-RW discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.dvdram</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can write to DVD-RAM discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.dvdplusr</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can write to DVD+R discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.dvdplusrw</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can blank and write to DVD+RW discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.dvdplusrwdl</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can blank and write to DVD+RW Dual-Layer discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.dvdplusrdl</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can write to DVD+R Dual-Layer discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.bd</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can read Blu-ray ROM discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.bdr</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can write to Blu-ray Recordable discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.bdre</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can write to Blu-ray Rewritable discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.hddvd</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can read Read-only HD DVD discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.hddvdr</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can write to Write-once HD DVD discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.hddvdrw</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can write to Rewritable HD DVD discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.mrw</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can read MRW (Mount Rainier Rewrite) discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.mrw_w</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE when the optical drive can write MRW (Mount Rainier Rewrite) discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.mo</code> (bool)
+              </td><td> </td><td>No</td><td>TRUE when the optical drive is a MO (Magneto Optical) device.</td></tr><tr><td>
+                <code class="literal">storage.cdrom.support_multisession</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE if the drive can read multisession discs</td></tr><tr><td>
+                <code class="literal">storage.cdrom.support_media_changed</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE if the drive can generate media changed events</td></tr><tr><td>
+                <code class="literal">storage.cdrom.read_speed</code> (int)
+              </td><td> </td><td>Yes</td><td>The maximum reading speed, in kb/s</td></tr><tr><td>
+                <code class="literal">storage.cdrom.write_speed</code> (int)
+              </td><td> </td><td>Yes</td><td>The maximum writing speed, in kb/s</td></tr><tr><td>
+                <code class="literal">storage.cdrom.write_speeds</code> (strlist)
+              </td><td> </td><td>No</td><td>By the device supported write speeds in kb/s</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-storage-linux-raid"></a>
+        storage.linux_raid namespace
+      </h3></div></div></div><p>
+        This namespace is used to describe logical Software RAID
+        devices under Linux using the <code class="literal">md</code> driver. By
+        and large, all the same properties under
+        the <code class="literal">storage</code> name space applies except
+        that <code class="literal">storage.serial</code> is set to the UUID of
+        the RAID set, <code class="literal">storage.firmware_version</code> is
+        set to the version of the <code class="literal">md</code> driver and the
+        value of <code class="literal">storage.hotpluggable</code> is taken from
+        the enclosing drive of the first RAID component
+        encountered. In addition, the following properties are
+        available.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">storage.linux_raid.level</code> (string)
+              </td><td> </td><td>Yes</td><td>the RAID level of the device as reported by the kernel (linear, raid0, raid1, raid4, raid5, raid6, raid10)</td></tr><tr><td>
+                <code class="literal">storage.linux_raid.sysfs_path</code> (string)
+              </td><td> </td><td>Yes</td><td>sysfs path of device, e.g. /sys/block/md0</td></tr><tr><td>
+                <code class="literal">storage.linux_raid.num_components</code> (int)
+              </td><td> </td><td>Yes</td><td>Number of components in the RAID array</td></tr><tr><td>
+                <code class="literal">storage.linux_raid.num_components_active</code> (int)
+              </td><td> </td><td>Yes</td><td>
+                Number of active components in the RAID array. If less
+                than <code class="literal">storage.linux_raid.num_components</code>
+                it means that the RAID array is running in degraded
+                mode.
+              </td></tr><tr><td>
+                <code class="literal">storage.linux_raid.components</code> (strlist)
+              </td><td> </td><td>Yes</td><td>UDI's of the volumes constituting the array.</td></tr><tr><td>
+                <code class="literal">storage.linux_raid.is_syncing</code> (bool)
+              </td><td> </td><td>Yes</td><td>TRUE if, and only if, the array is currently syncing</td></tr><tr><td>
+                <code class="literal">storage.linux_raid.sync.action</code> (string)
+              </td><td> </td><td>only if <code class="literal">.is_syncing</code> is TRUE</td><td>The syncing mechanism as reported by the kernel (idle, resync, check, repair, recover)</td></tr><tr><td>
+                <code class="literal">storage.linux_raid.sync.progress</code> (double)
+              </td><td> </td><td>only if <code class="literal">.is_syncing</code> is TRUE</td><td>Number between 0 and 1 representing progress of the sync operation. This is updated regulary when syncing is happening.</td></tr><tr><td>
+                <code class="literal">storage.linux_raid.sync.speed</code> (uint64)
+              </td><td> </td><td>only if <code class="literal">.is_syncing</code> is TRUE</td><td>Speed of the sync operation, in kB/s. This is updated regulary when syncing is happening.</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-net"></a>
+        net namespace
+      </h3></div></div></div><p>
+        This namespace is used to describe networking devices and
+        their capabilities.Such device objects will have the
+        capability <code class="literal">net</code> and they will export the
+        properties below. This namespace only describe the generic
+        aspect of networking devices; specific networking technologies
+        such as IEEE 802.3, IEEE 802.11 and Bluetooth have separate
+       namespaces.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">net.address</code> (string)
+              </td><td> </td><td>Yes</td><td>Hardware address as a string. Is hardware dependant</td></tr><tr><td>
+                <code class="literal">net.arp_proto_hw_id</code> (string)
+              </td><td> </td><td>Yes</td><td>ARP protocol hardware identifier</td></tr><tr><td>
+                <code class="literal">net.interface</code> (string)
+              </td><td> </td><td>Yes</td><td>Name of the interface; may change if an interface is
+                renamed
+              </td></tr><tr><td>
+                <code class="literal">net.interface_up</code> (bool)
+              </td><td> </td><td>No</td><td>Whether the interface is up</td></tr><tr><td>
+                <code class="literal">net.linux.ifindex</code> (string)
+              </td><td> </td><td>Yes (only on Linux)</td><td>Index of the interface</td></tr><tr><td>
+                <code class="literal">net.originating_device</code> (string)
+              </td><td> </td><td>Yes</td><td>UDI of the device the network device is bound to.</td></tr><tr><td>
+                <code class="literal">net.media</code> (string)
+              </td><td>example: Ethernet</td><td>Yes</td><td>Textual description of the networking media</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-net-80203"></a>
+        net.80203 namespace
+      </h3></div></div></div><p>
+        Ethernet networking devices is described in this namespace
+        for device objects with the capability
+        <code class="literal">net.80203</code>.
+        Note that device
+        objects can only have the <code class="literal">net.80203</code> capability
+        if they already have the capability <code class="literal">net</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">net.80203.link</code> (bool)
+              </td><td> </td><td>
+                Only if the <code class="literal">net.80203</code> capability is set
+                and <code class="literal">net.interface_up</code> is
+                <code class="literal">TRUE</code>.
+              </td><td>True if the ethernet adaptor is connected to a
+                another transceiver. NOTE: property not implemented yet.
+              </td></tr><tr><td>
+                <code class="literal">net.80203.rate</code> (uint64)
+              </td><td>example: 100000000</td><td>
+                Only if the <code class="literal">net.80203</code> capability is set
+                and <code class="literal">net.80203.link</code> is
+                <code class="literal">TRUE</code>.
+              </td><td>Bandwidth of connection, in bits/s. NOTE: property not
+                implemented yet.
+              </td></tr><tr><td>
+                <code class="literal">net.80203.mac_address</code> (uint64)
+              </td><td>example: 0x0010605d8ef4</td><td>
+                Only if the <code class="literal">net.80203</code> is set
+              </td><td>48-bit address</td></tr></tbody></table></div><p>
+      </p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-net-80211"></a>
+        net.80211 namespace
+      </h3></div></div></div><p>
+        Wireless ethernet networking devices is described in this namespace
+        for device objects with the capability
+        <code class="literal">net.80211</code>.
+        Note that device
+        objects can only have the <code class="literal">net.80211</code> capability
+        if they already have the capability <code class="literal">net</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">net.80211.mac_address</code> (uint64)
+              </td><td>example: 0x0010605d8ef4</td><td>
+                Only if the <code class="literal">net.80211</code> capability is set
+              </td><td>48-bit address</td></tr></tbody></table></div><p>
+      </p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-net-bluetooth"></a>
+        net.bluetooth namespace
+      </h3></div></div></div><p>
+        Bluetooth ethernet networking devices is described in this namespace
+        for device objects with the capability
+        <code class="literal">net.bluetooth</code>.
+        Note that device
+        objects can only have the <code class="literal">net.bluetooth</code> capability
+        if they already have the capability <code class="literal">net</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">net.bluetooth.mac_address</code> (uint64)
+              </td><td>example: 0x0010605d8ef4</td><td>
+                Only if the <code class="literal">net.bluetooth</code> capability is set
+              </td><td>48-bit address</td></tr><tr><td>
+                <code class="literal">net.bluetooth.name</code> (string)
+              </td><td>example: Network Access Point Service</td><td>
+                Only if the <code class="literal">net.bluetooth</code> capability is set and Bluez is being used.
+              </td><td>Displayable Name for network connection</td></tr><tr><td>
+                <code class="literal">net.bluetooth.uuid</code> (string)
+              </td><td>example: 00001116-0000-1000-8000-00805f9b34fb</td><td>
+                Only if the <code class="literal">net.bluetooth</code> capability is set and Bluez is being used.
+              </td><td>Universal Unique Identifier for network connection</td></tr></tbody></table></div><p>
+      </p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-net-irda"></a>
+        net.irda namespace
+      </h3></div></div></div><p>
+        IrDA (Infrared Data Association) Networking devices are described in 
+       this namespace for device objects with the capability
+        <code class="literal">net.irda</code>.
+        Note that device objects can only have the <code class="literal">net.irda</code> 
+       capability if they already have the capability <code class="literal">net</code>.
+      </p><p>
+      </p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-net-80211control"></a>
+        net.80211control namespace
+      </h3></div></div></div><p>
+        Control devices for Wireless ethernet networking devices are described in 
+       this namespace for device objects with the capability
+        <code class="literal">net.80211control</code>.
+        Note that device objects can only have the <code class="literal">net.80211control</code> 
+       capability if they already have the capability <code class="literal">net</code>.
+       Warning: You should know what you do if you touch this devices. They are 
+       not always stable and can cause (kernel) crashes (on linux).
+      </p><p>
+      </p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-input"></a>
+        input namespace
+      </h3></div></div></div><p>
+        This namespace is concerned with human input devices such as
+        keyboards, mice, pointing devices and game controllers. If a
+        device object has the capability <code class="literal">input</code> then
+        the following properties are available
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">input.device</code> (string)
+              </td><td> </td><td>Yes</td><td>Special device file for recieving input events</td></tr><tr><td>
+                <code class="literal">input.x11_driver</code> (string)
+              </td><td>e.g. "evdev"</td><td>No</td><td>X11 input driver to use</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-input-keys"></a>
+        input.keys namespace
+      </h3></div></div></div><p>
+        The input device have keys that can be pressed. No namespace
+        specific properties.
+      </p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-input-keypad"></a>
+        input.keypad namespace
+      </h3></div></div></div><p>
+        The input device have keypad keys. No namespace
+        specific properties.
+      </p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-input-keyboard"></a>
+        input.keyboard namespace
+      </h3></div></div></div><p>
+        The input device is a normal keyboard. No namespace specific
+        properties.
+      </p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-input-mouse"></a>
+        input.mouse namespace
+      </h3></div></div></div><p>
+        The input device is a mouse. No namespace specific
+        properties.
+      </p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-input-switch"></a>
+        input.switch namespace
+      </h3></div></div></div><p>
+        The input device is a switch, e.g. it has buttons with
+        state. No namespace specific properties.
+      </p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-input-joystick"></a>
+        input.joystick namespace
+      </h3></div></div></div><p>
+        The input device is a joystick. No namespace specific
+        properties.
+      </p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-input-tablet"></a>
+        input.tablet namespace
+      </h3></div></div></div><p>
+        The input device is a tablet. No namespace specific
+        properties.
+      </p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-input-keymap"></a>
+        input.keymap namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">input.keymap</code>
+        provide facilities to remap keyboard buttons.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">input.keymap.data</code> (strlist)
+              </td><td>e.g. "e017:brightnessup"</td><td>No</td><td>
+                The scancode is represented in hex and the keycode name as
+                as string. The keycode name is not case sensitive.
+                On Linux, the keycode name should be the same constant as
+                present in /usr/include/linux/input.h with the 'KEY_'
+                prefix removed, e.g. 'KEY_SLEEP' -&gt; 'sleep'.
+                You can append as many <code class="literal">input.keymap.data</code>
+                values as there are keys to remap.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-input-xkb"></a>
+        input.xkb namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">input.keys</code>
+        can provide information about their physical layout.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">input.xkb.rules</code> (string)
+              </td><td>e.g. "base"</td><td>Yes</td><td>
+                XKB rules file to use; 'base' is standard, but 'xorg'
+                or 'xfree86' may be needed for backwards compatibility
+                with very old versions of XKB data.
+              </td></tr><tr><td>
+                <code class="literal">input.xkb.model</code> (string)
+              </td><td>e.g. "logicdp"</td><td>Yes</td><td>
+                Physical keyboard model (e.g. Logitech Cordless Freedom
+                Pro), as given to XKB.
+              </td></tr><tr><td>
+                <code class="literal">input.xkb.layout</code> (string)
+              </td><td>e.g. "us"</td><td>Yes</td><td>
+                Keyboard layout (as engraved on the keys).
+              </td></tr><tr><td>
+                <code class="literal">input.xkb.variant</code> (string)
+              </td><td>e.g. "nodeadkeys"</td><td>No</td><td>
+                Variant of the XKB layout (if any) to use.
+              </td></tr><tr><td>
+                <code class="literal">input.xkb.options</code> (strlist)
+              </td><td>e.g. "ctrl:nocaps"</td><td>No</td><td>
+                Options to be provided to XKB.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-pcmcia_socket"></a>
+        pcmcia_socket namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">pcmcia_socket</code>
+        represent bridge devices (the actual bus of the device may differ)
+        that PCMCIA cards can be attached to. The following properties are
+        available.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">pcmcia_socket.number</code> (int)
+              </td><td> </td><td>Yes</td><td>PCMCIA socket number, starting from zero</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-printer"></a>
+        printer namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">printer</code>
+        represent printers. The following properties are available.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">printer.device</code> (string)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr><tr><td>
+                <code class="literal">printer.vendor</code> (string)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr><tr><td>
+                <code class="literal">printer.product</code> (string)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr><tr><td>
+                <code class="literal">printer.serial</code> (string)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr><tr><td>
+                <code class="literal">printer.description</code> (string)
+              </td><td> </td><td>Yes</td><td>TODO</td></tr><tr><td>
+                <code class="literal">printer.commandset</code> (strlist)
+              </td><td> </td><td>No</td><td>List of supported commands / printer languages.</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-portable_audio_player"></a>
+        portable_audio_player namespace
+      </h3></div></div></div><p>
+        Device objects with the capability
+        <code class="literal">portable_audio_player</code> represent portable
+        audio players that can be attached to a computer to exchange
+        files. They can also playback audio. Sometimes they can also
+        record audio. This capability can't, in general, be reliably
+        probed from the hardware so the information needs to be merged
+        from either device information files or callouts. Therefore
+        this capability should be merged on the appropriate device
+        object that represents the addressable piece of hardware that
+        is the portable music player; for USB devices this would be
+        the device object representing the appropriate USB
+        interface. The following properties are available:
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">portable_audio_player.access_method.protocols</code> (strlist)
+              </td><td>example: storage ipod mtp pde iriver karma</td><td>No</td><td>
+                Indicates transfer protocols that this device can speak.
+                <code class="literal">storage</code> indicates USB Mass Storage (UMS) is an access
+                protocol.  <code class="literal">ipod</code> indicates UMS plus an iTunes-style database.
+                <code class="literal">mtp</code> indicates a device using Microsoft's Media Transfer Protocol.
+                Arbitrary values for newer or obscure protocols are allowed but
+                entities providing this information should try to ensure that
+                they are not duplicating protocols under a different name.
+              </td></tr><tr><td>
+                <code class="literal">portable_audio_player.access_method.drivers</code> (strlist)
+              </td><td>example: libgpod, libmtp, libnjb, libifp, libkarma</td><td>No</td><td>
+                Indicates installed device driver libraries that can
+                handle this device.  These drivers can export information
+                in <code class="literal">portable_audio_player.[drivername]</code> sub-namespaces.
+                Can also be used by libraries or programs providing extra device information
+                to indicate the presence of this information in the appropriate sub-namespace.
+              </td></tr><tr><td>
+                <code class="literal">portable_audio_player.[drivername].protocol</code> (strlist)
+              </td><td>example: mtp</td><td>Yes</td><td>
+                This entry is required for drivers listed in
+                <code class="literal">portable_audio_player.access_method.drivers</code>. Indicates which
+                protocol in <code class="literal">portable_audio_player.access_method.protocols</code>
+                a particular driver will use.  If the driver is providing information only, this
+                should be set to <code class="literal">information</code>.
+              </td></tr><tr><td>
+                <code class="literal">portable_audio_player.output_formats</code> (strlist)
+              </td><td>example: audio/mpeg audio/x-ms-wma</td><td>Yes</td><td>
+                A string list of MIME-types representing the kind of audio
+                formats that the device can play back.
+              </td></tr><tr><td>
+                <code class="literal">portable_audio_player.input_formats</code> (strlist)
+              </td><td>example: audio/x-wav</td><td>Yes</td><td>
+                A string list of MIME-types representing the kind of audio
+                formats that the device can record. If empty, it means that
+                the device is not capable of recording.
+              </td></tr><tr><td>
+                <code class="literal">portable_audio_player.folder_depth </code> (int)
+              </td><td>example: 1 (If the device only supports one sub-folder)</td><td>No</td><td>
+                If portable_audio_player.access_method.protocols contains "storage",
+                this tells applications exactly how deep of directory hierarchies
+                files should be placed in.  If all files are put in a
+                sub-folder (with the audio_folders property), only the depth within
+                that sub-folder should be entered here. If the device does not have
+                a limit, do not set this property.
+              </td></tr><tr><td>
+                <code class="literal">portable_audio_player.audio_folders</code> (strlist)
+              </td><td>example: music/ voice/ linein/</td><td>No</td><td>
+                If portable_audio_player.access_method.protocols contains "storage",
+                this may contain a string list of folders in which music
+                can be found.  Paths are relative to the mount point of the
+                device. If there is one or more entry in this property, the
+                first one is where files will be written to by applications.
+                Do not enter a folder and a parent of that folder.
+                If the device places files in its root directory, then do not
+                set this property.
+              </td></tr><tr><td>
+                <code class="literal">portable_audio_player.playlist_format</code> (strlist)
+              </td><td>example: audio/x-mpegurl audio/x-somethingelse</td><td>No</td><td>
+                A string list of the MIME-type of the playlist formats accepted by
+                this device.  Leave blank if none.
+              </td></tr><tr><td>
+                <code class="literal">portable_audio_player.playlist_path</code> (string)
+              </td><td>examples: playlists/%File or Playlist.m3u</td><td>No</td><td>
+                Set to the path to which playlists should be written.  Leave
+                blank if playlist files are not supported.  If the device supports a single playlist with a specific name/path,
+                set this to the path relative to the mount point that it should be saved to.  If it supports multiple
+                playlists, use the %File variable as needed.  Applications are responsible for substituting %File with the
+                desired playlist file name, noting that it's use in this string is optional.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-alsa"></a>
+        alsa namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">alsa</code>
+        represent all the streams available through ALSA on a soundcard.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">alsa.card</code> (int)
+              </td><td> </td><td>Yes</td><td>
+                Card number in system as registered by ALSA.
+              </td></tr><tr><td>
+                <code class="literal">alsa.card_id</code> (string)
+              </td><td>
+                Examples: <code class="literal">I82801DBICH4</code>, <code class="literal">MP3</code>
+              </td><td>No</td><td>
+                Textual description of the card.
+              </td></tr><tr><td>
+                <code class="literal">alsa.device</code> (int)
+              </td><td> </td><td>Yes</td><td>
+                Device number assigned by ALSA for a current card.
+              </td></tr><tr><td>
+                <code class="literal">alsa.device_file</code> (string)
+              </td><td> </td><td>Yes</td><td>
+                The device node to access the ALSA device.
+              </td></tr><tr><td>
+                <code class="literal">alsa.device_id</code> (string)
+              </td><td>
+                Examples: <code class="literal">Intel 82801DB-ICH4 MIC2 ADC</code>
+              </td><td>No</td><td>
+                Textual description of the specific device for a card
+              </td></tr><tr><td>
+                <code class="literal">alsa.device_pcm_class</code> (string)
+              </td><td> </td><td>No</td><td>
+                The PCM class of the device.
+              </td></tr><tr><td> </td><td>generic</td><td> </td><td>
+                A standard PCM sound device (SND_PCM_CLASS_GENERIC).
+              </td></tr><tr><td> </td><td>multi</td><td> </td><td>
+                A multichannel device PCM sound device (SND_PCM_CLASS_MULTI) which 
+               e.g. contains a generic and a modem device.
+              </td></tr><tr><td> </td><td>digitizer</td><td> </td><td>
+                A PCM digitizer device (SND_PCM_CLASS_DIGITIZER).
+              </td></tr><tr><td> </td><td>modem</td><td> </td><td>
+                A PCM modem device (SND_PCM_CLASS_MODEM).
+              </td></tr><tr><td> </td><td>unknown</td><td> </td><td>
+                The value is 'unknown' if the kernel provide no information about the 
+               PCM device class of the device (e.g. the file pcm_class is missing).
+              </td></tr><tr><td> </td><td>none</td><td> </td><td>
+                The value is 'none' if this there is no PCM class for this device.
+              </td></tr><tr><td>
+                <code class="literal">alsa.originating_device</code> (string)
+              </td><td> </td><td>Yes</td><td>
+                UDI of the device the ALSA device is bound to.
+              </td></tr><tr><td>
+                <code class="literal">alsa.type</code> (string)
+              </td><td> </td><td>Yes</td><td>
+                The type of the stream.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">control</code>
+              </td><td> </td><td>
+                Stream is control device.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">capture</code>
+              </td><td> </td><td>
+                Stream is capture device.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">midi</code>
+              </td><td> </td><td>
+                Stream is MIDI device.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">playback</code>
+              </td><td> </td><td>
+                Stream is playback device.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">unknown</code>
+              </td><td> </td><td>
+                The type of the device is unknown.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">hw_specific</code>
+              </td><td> </td><td>
+                This is a hardware specific device (as e.g. from snd_fm801 for Fortemedia FM801 
+               PCI Audio). The driver can use it freely for purposes that are not covered by 
+               standard ALSA API. 
+              </td></tr><tr><td> </td><td>
+                <code class="literal">timer</code>
+              </td><td> </td><td>
+                Stream is the global ALSA timer device.
+                This means, the device is for all ALSA devices/cards.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">sequencer</code>
+              </td><td> </td><td>
+                Stream is the global ALSA sequencer device.
+                This means, the device is for all ALSA devices/cards.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">unknown</code>
+              </td><td> </td><td>
+                Stream is unknown device.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-oss"></a>
+        oss namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">oss</code>
+        represent all the streams available through OSS on a soundcard.
+        OSS devices could be emulated by ALSA.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">oss.card</code> (int)
+              </td><td> </td><td>Yes</td><td>
+                Card number in system as registered by OSS (and/or ALSA).
+              </td></tr><tr><td>
+                <code class="literal">oss.card_id</code> (string)
+              </td><td>
+                Examples: <code class="literal">I82801DBICH4</code>, <code class="literal">MP3</code>
+              </td><td>No</td><td>
+                Textual description of the card.
+              </td></tr><tr><td>
+                <code class="literal">oss.device</code> (int)
+              </td><td> </td><td>Yes</td><td>
+                Device number assigned by OSS/ALSA for a current card.
+              </td></tr><tr><td>
+                <code class="literal">oss.device_file</code> (string)
+              </td><td> </td><td>Yes</td><td>
+                The device node to access the OSS device.
+              </td></tr><tr><td>
+                <code class="literal">oss.device_id</code> (string)
+              </td><td>
+                Examples: <code class="literal">Intel 82801DB-ICH4 MIC2 ADC</code>
+              </td><td>No</td><td>
+                Textual description of the specific device for a card
+              </td></tr><tr><td>
+                <code class="literal">oss.originating_device</code> (string)
+              </td><td> </td><td>Yes</td><td>
+                UDI of the device the OSS device is bound to.
+              </td></tr><tr><td>
+                <code class="literal">oss.type</code> (string)
+              </td><td> </td><td>Yes</td><td>
+                The type of the stream.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">mixer</code>
+              </td><td> </td><td>
+                Stream is control/mixer device.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">pcm</code>
+              </td><td> </td><td>
+                Stream is PCM device.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">midi</code>
+              </td><td> </td><td>
+                Stream is MIDI device.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">sequencer</code>
+              </td><td> </td><td>
+                Stream is a global OSS sequencer device.
+                This means, the device is for all OSS devices/cards.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">unknown</code>
+              </td><td> </td><td>
+                Stream is unknown device.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-camera"></a>
+        camera namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">camera</code>
+        represent digital still cameras that can be attached to a
+        computer to exchange files. This does not include card readers
+        for memory cards used for cameras. This capability can't, in
+        general, be reliably probed from the hardware so the
+        information needs to be merged from either device information
+        files or callouts. Therefore this capability should be merged
+        on the appropriate device object that represents the
+        addressable piece of hardware that is the digital still
+        camera; for USB devices this would be the device object
+        representing the appropriate USB interface. The following
+        properties are available:
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">camera.access_method</code> (string)
+              </td><td> </td><td>Yes</td><td>This property defines how the device is accessed </td></tr><tr><td> </td><td>storage</td><td> </td><td>
+                The device is accessed as a Mass Storage device
+                through a kernel driver.  Application Developers
+                should descent down the device object tree to find the
+                device object of capability
+                <code class="literal">storage</code> in order to access the
+                device.
+              </td></tr><tr><td> </td><td>user</td><td> </td><td>
+                The device is accessed from userspace through
+                a userspace driver.
+              </td></tr><tr><td> </td><td> </td><td> </td><td> </td></tr><tr><td>
+                <code class="literal">camera.libgphoto2.support</code> (bool)
+              </td><td> </td><td>No</td><td>
+                If true, the device is supported by a userspace driver
+                from the libgphoto2 project.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-scanner"></a>
+        scanner namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">scanner</code>
+        represent image scanners. This capability should be merged
+        on the appropriate device object that represents the
+        addressable piece of hardware that is the digital still
+        camera; for USB devices this would be the device object
+        representing the appropriate USB interface. The following
+        properties are available:
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">scanner.access_method</code> (string)
+              </td><td> </td><td>Yes</td><td>This property defines how the device is accessed </td></tr><tr><td> </td><td>proprietary</td><td> </td><td>
+                The device is accessed from userspace through
+                a userspace driver such as SANE.
+              </td></tr><tr><td> </td><td> </td><td> </td><td> </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-laptop-panel"></a>
+        laptop_panel namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">laptop_panel</code>
+        represent devices capable of changing the brightness of the display.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">laptop_panel.num_levels</code> (int)
+              </td><td> </td><td>Yes</td><td>
+                The brightness levels supported by the adaptor.
+              </td></tr><tr><td>
+                <code class="literal">laptop_panel.access_method</code> (string)
+              </td><td> </td><td>Yes</td><td>
+                The access method to use in scripts, e.g. pmu, toshiba, ibm, sony.
+              </td></tr><tr><td>
+                <code class="literal">laptop_panel.brightness_in_hardware</code> (bool)
+              </td><td> </td><td>No</td><td>
+                On some laptops, the brightness control is all done in hardware
+                but the hardware also synthesizes keypresses when the
+                brightness is changed.
+                If this key is set true, then any power manager software should
+                not attempt to set any new values on brightness keypress, as it
+                may cause the panel to flash uncontrollably.
+              </td></tr></tbody></table></div><p>
+        The following methods exist on the interface
+        <code class="literal">org.freedesktop.Hal.Device.LaptopPanel</code>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method (parameter types)</th><th>Parameters</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">SetBrightness</code> (integer)
+              </td><td>
+                The hardware brightness state, which should be between 0 and 
+                <code class="literal">laptop_panel.num_levels</code> - 1.
+              </td><td>No</td><td>
+                This method adjusts the brightness on an laptop screen.
+                The values are returned as hardware values rather than
+                percentages as we cannot easily to floating point rounding in
+                shell code and therefore use the raw values to prevent integer
+                rounding errors.
+              </td></tr><tr><td>
+                integer <code class="literal">GetBrightness</code> (void)
+              </td><td>
+                Returns the hardware brightness state, which should be
+                between 0 and <code class="literal">laptop_panel.num_levels</code> - 1.
+              </td><td>No</td><td>
+                This method gets the hardware brightness of the laptop screen,
+                which we may need to do fairly regually on hardware that
+                changes the values in hardware without a software event.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-ac_adapter"></a>
+        ac_adapter namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">ac_adapter</code>
+        represent all the devices capable of powering the system from AC power
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ac_adapter.present</code> (bool)
+              </td><td> </td><td>Yes</td><td>
+                The state of the adapter, i.e. whether it is providing power to
+                the unit from mains power.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-battery"></a>
+        battery namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">battery</code>
+        represent all the devices having some battery (in many cases -
+        rechargeable) inside.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">battery.present</code> (bool)
+              </td><td> </td><td>Yes</td><td>
+                This is present as some smart batteries can have acpi/pmu
+                entries, and be physically missing.
+              </td></tr><tr><td>
+                <code class="literal">battery.type</code> (string)
+              </td><td> </td><td>Yes</td><td>
+                This property defines the type of the device holding the
+                battery. This property is defined for the development
+                simplicity - battery indicators can use it to find the
+                proper iconic representation.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">pda</code>
+              </td><td> </td><td>
+                The device containing the battery is a personal digital
+                assistant, e.g. a device that looks like a handheld computer
+                to do specific tasks such as keeping notes or containing
+                a personal database
+              </td></tr><tr><td> </td><td>
+                <code class="literal">ups</code>
+              </td><td> </td><td>
+                A battery powered power supply that is
+                guaranteed to provide power to a computer in the event of
+                interruptions in the incoming electrical power. Most of the
+                time this is an external device.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">primary</code>
+              </td><td> </td><td>
+                The battery is a primary power source for the system - an
+                example are laptop batteries.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">mouse</code>
+              </td><td> </td><td>
+                The device containing the battery is a mouse.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">keyboard</code>
+              </td><td> </td><td>
+                The device containing the battery is a keyboard.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">keyboard_mouse</code>
+              </td><td> </td><td>
+                The device containing the battery is a combined mouse and keyboard.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">camera</code>
+              </td><td> </td><td>
+                The device containing the battery is a camera.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">usb</code>
+              </td><td> </td><td>
+                The device containing the battery is a generic usb device.
+              </td></tr><tr><td> </td><td>
+                <code class="literal">unknown</code>
+              </td><td> </td><td>
+                The device containing the battery is not covered by other types.
+              </td></tr><tr><td>
+                <code class="literal">battery.charge_level.unit</code> (string)
+              </td><td>Examples:
+                <code class="literal">mWh</code>,
+                <code class="literal">percent</code>
+              </td><td>No</td><td>
+                The physical unit used by the charge level properties
+                (maximum and current). In many cases, this property is
+                omitted - which indicates that the charge properties
+                are measured in some unknown units.
+                The units should never be mAh as this is not a measurement
+                of charge.
+              </td></tr><tr><td>
+                <code class="literal">battery.charge_level.design</code> (int)
+              </td><td> </td><td>Yes</td><td>
+                The maximum level of charge the device was designed for.
+                Measured in <code class="literal">"battery.charge_level.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.charge_level.last_full</code> (int)
+              </td><td> </td><td>Yes</td><td>
+                The maximum level of charge the device could hold the last
+                time it was full.
+                Measured in <code class="literal">"battery.charge_level.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.charge_level.current</code> (int)
+              </td><td> </td><td>Yes</td><td>
+                The current level of charge which the device can is holding.
+                Measured in <code class="literal">"battery.charge_level.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.charge_level.rate</code> (int)
+              </td><td> </td><td>No</td><td>
+                The discharge/charge rate measured
+                in <code class="literal">"battery.charge_level.unit"</code>
+                units per second.
+              </td></tr><tr><td>
+                <code class="literal">battery.charge_level.warning</code> (int)
+              </td><td> </td><td>No</td><td>
+                Once the charge level of the battery drops below this value its
+                state changes to 'warning'.
+                Measured in <code class="literal">"battery.charge_level.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.charge_level.low</code> (int)
+              </td><td> </td><td>No</td><td>
+                Once the charge level of the battery drops below this value its
+                state changes to 'low'.
+                Measured in <code class="literal">"battery.charge_level.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.charge_level.granularity_1</code> (int)
+              </td><td> </td><td>No</td><td>
+                Granularity value one of the battery measured
+                in <code class="literal">"battery.charge_level.unit"</code>
+                units .
+              </td></tr><tr><td>
+                <code class="literal">battery.charge_level.granularity_2</code> (int)
+              </td><td> </td><td>No</td><td>
+                Granularity value two of the battery measured
+                in <code class="literal">"battery.charge_level.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.reporting.unit</code> (string)
+              </td><td>Examples:
+                <code class="literal">mWh</code>,
+                <code class="literal">mAh</code>,
+                <code class="literal">percent</code>
+              </td><td>No</td><td>
+                The physical unit used by the charge level properties
+                (maximum and current) as reported by the hardware.
+                In many cases, this property is omitted - which indicates
+                that the charge properties are measured in some unknown units.
+              </td></tr><tr><td>
+                <code class="literal">battery.reporting.design</code> (int)
+              </td><td> </td><td>Yes</td><td>
+                The maximum level of charge the device was designed for,
+                as reported by the hardware.
+                Measured in <code class="literal">"battery.reporting.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.reporting.last_full</code> (int)
+              </td><td> </td><td>No</td><td>
+                The maximum level of charge the device could hold the last
+                time it was full, as reported by the hardware.
+                Measured in <code class="literal">"battery.reporting.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.reporting.current</code> (int)
+              </td><td> </td><td>No</td><td>
+                The current level of charge which the device is holding,
+                as reported by the hardware.
+                Measured in <code class="literal">"battery.reporting.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.reporting.rate</code> (int)
+              </td><td> </td><td>No</td><td>
+                The discharge/charge rate as reported by the hardware measured
+                in <code class="literal">"battery.reporting.unit"</code>
+                units per second.
+              </td></tr><tr><td>
+                <code class="literal">battery.reporting.warning</code> (int)
+              </td><td> </td><td>No</td><td>
+                Once the hardware charge level of the battery drops below
+                this value its state changes to 'warning'.
+                Measured in <code class="literal">"battery.reporting.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.reporting.low</code> (int)
+              </td><td> </td><td>No</td><td>
+                Once the hardware charge level of the battery drops below
+                this value its state changes to 'low'.
+                Measured in <code class="literal">"battery.reporting.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.reporting.granularity_1</code> (int)
+              </td><td> </td><td>No</td><td>
+                Hardware granularity value one of the battery measured
+                in <code class="literal">"battery.reporting.unit"</code>
+                units .
+              </td></tr><tr><td>
+                <code class="literal">battery.reporting.granularity_2</code> (int)
+              </td><td> </td><td>No</td><td>
+                Hardware granularity value two of the battery measured
+                in <code class="literal">"battery.reporting.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.charge_level.capacity_state</code> (string)
+              </td><td>
+                Examples: <code class="literal">ok</code>, <code class="literal">critical</code>
+              </td><td>No</td><td>
+                The capacity state of the battery.
+              </td></tr><tr><td>
+                <code class="literal">battery.voltage.unit</code> (string)
+              </td><td>
+                Examples: <code class="literal">mV</code>
+              </td><td>No</td><td>
+                The physical measurement unit used by the voltage properties
+                (design and current).
+              </td></tr><tr><td>
+                <code class="literal">battery.voltage.design</code> (int)
+              </td><td> </td><td>Yes</td><td>
+                The voltage level for which the battery is designed for.
+                Measured in <code class="literal">"battery.voltage.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.voltage.current</code> (int)
+              </td><td> </td><td>Yes</td><td>
+                The voltage level currently emitted by the battery.
+                Measured in <code class="literal">"battery.voltage.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.alarm.unit</code> (string)
+              </td><td>
+                Examples: <code class="literal">mWh</code>, <code class="literal">mAh</code>
+              </td><td>No</td><td>
+                The physical measurement unit used by the alarm property.
+              </td></tr><tr><td>
+                <code class="literal">battery.alarm.design</code> (int)
+              </td><td> </td><td>No</td><td>
+                Once the charge level of the battery drops below this value
+                its state changes to 'alarm'.
+                Measured in <code class="literal">"battery.alarm.unit"</code>
+                units.
+              </td></tr><tr><td>
+                <code class="literal">battery.remaining_time</code> (int)
+              </td><td> </td><td>No</td><td>
+                Remaining time, in seconds, that the battery can provide
+                power (if discharging) or the time until charged (if charging).
+                This is an estimate and may be imprecise.
+                This key is not present for invalid data.
+              </td></tr><tr><td>
+                <code class="literal">battery.remaining_time.calculate_per_time</code> (bool)
+              </td><td> </td><td>No</td><td>
+                If this property is <code class="literal">true</code> the
+                <code class="literal">battery.remaining_time</code> becomes guessed from
+                <code class="literal">battery.charge_level.current</code> and time.
+              </td></tr><tr><td>
+                <code class="literal">battery.charge_level.percentage</code> (int)
+              </td><td> </td><td>No</td><td>
+                Charge, normalised to percent. This is useful if an application
+                does not want to process the raw values and do all the extra
+                checks on the result. This key is not present for invalid data.
+              </td></tr><tr><td>
+                <code class="literal">battery.is_rechargeable</code> (bool)
+              </td><td> </td><td>No</td><td>
+                True if the battery unit is rechargeable, false if its is
+                one-time (disposable after one usage).
+              </td></tr><tr><td>
+                <code class="literal">battery.rechargeable.is_charging</code> (bool)
+              </td><td> </td><td>
+                Only if <code class="literal">battery.is_rechargeable</code> is TRUE
+              </td><td>
+                TRUE if, and only if, the battery is charging.
+              </td></tr><tr><td>
+                <code class="literal">battery.rechargeable.is_discharging</code> (bool)
+              </td><td> </td><td>
+                Only if <code class="literal">battery.is_rechargeable</code> is TRUE
+              </td><td>
+                TRUE if, and only if, the battery is discharging.
+              </td></tr><tr><td>
+                <code class="literal">battery.command_interface</code> (string)
+              </td><td> </td><td>No</td><td>
+                The abstract name allowing daemons and/or user-level apps
+                to distinguish some groups of devices having similar
+                programming  interface. Introduced mostly for the daemons'
+                coding simplicity.
+              </td></tr><tr><td>
+                <code class="literal">battery.vendor</code> (string)
+              </td><td> </td><td>No</td><td>
+                Vendor of the battery.
+              </td></tr><tr><td>
+                <code class="literal">battery.model</code> (string)
+              </td><td> </td><td>No</td><td>
+                Make of the battery.
+              </td></tr><tr><td>
+                <code class="literal">battery.reporting.technology</code> (string)
+              </td><td>example: LION</td><td>No</td><td>
+                The technology of the battery as reported by the hardware.
+              </td></tr><tr><td>
+                <code class="literal">battery.technology</code> (string)
+              </td><td>
+                lead-acid, lithium-ion, lithium-polymer,
+                nickel-metal-hydride, unknown
+              </td><td>No</td><td>
+                The technology of the battery processed to a few standard types.
+                This key is needed as the hardware often does not specify the
+                description text for a battery, and so we have to calculate it
+                from the output of <code class="literal">battery.reporting.technology</code>.
+              </td></tr><tr><td>
+                <code class="literal">battery.serial</code> (string)
+              </td><td> </td><td>No</td><td>
+                A string uniquely identifying the instance of the battery;
+                it will be different for two (otherwise) identical batteries.
+              </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-button"></a>
+        button namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">button</code>
+        represent the devices capable of providing a state to the system.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">button.type</code> (string)
+              </td><td> </td><td>No</td><td>The type of button</td></tr><tr><td> </td><td>lid</td><td> </td><td>
+                The switch on a laptop that senses whether the lid is
+                open or closed
+              </td></tr><tr><td> </td><td>power</td><td> </td><td>The main power button on the computer.</td></tr><tr><td> </td><td>sleep</td><td> </td><td>
+                The sleep button on a computer capable of putting the computer
+                into a suspend state
+              </td></tr><tr><td>
+                <code class="literal">button.has_state</code> (bool)
+              </td><td> </td><td>no</td><td>True if the button maintains state, e.g. can toggled on/off</td></tr><tr><td>
+                <code class="literal">button.state.value</code> (bool)
+              </td><td> </td><td>
+                Only when <code class="literal">button.has_state</code> is
+                TRUE
+              </td><td>State of the button, TRUE if it is enabled</td></tr></tbody></table></div><p>
+        Device objects with this capability may emit the following events.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Condition Name</th><th>Parameters</th><th>Example</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">ButtonPressed</code>
+              </td><td>
+                <code class="literal">button.type (string)</code>
+              </td><td>sleep</td><td>Emitted when a button is pressed</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-processor"></a>
+        processor namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">processor</code>
+        represent CPU's in the system.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">processor.number</code> (int)
+              </td><td> </td><td>Yes</td><td>
+                The internal processor number in the system, starting from zero
+              </td></tr><tr><td>
+                <code class="literal">processor.can_throttle</code> (bool)
+              </td><td> </td><td>No</td><td>
+                Whether the processor supports throttling to decrease it's
+                own clock speed
+              </td></tr><tr><td>
+                <code class="literal">processor.maximum_speed</code> (long)
+              </td><td>example: 2200</td><td>No</td><td>The maximum speed of the processor in units of MHz</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-light-sensor"></a>
+        light_sensor namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">sensor</code>
+        represent light sensors in the system.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">light_sensor.sensor_locations</code> (strlist)
+              </td><td> </td><td>Yes</td><td>The locations of the sensors</td></tr><tr><td>
+                <code class="literal">light_sensor.num_sensors</code> (int)
+              </td><td> </td><td>Yes</td><td>Number of physical sensors</td></tr><tr><td>
+                <code class="literal">light_sensor.num_levels</code> (int)
+              </td><td> </td><td>Yes</td><td>The number of levels of the sensors</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-power-management"></a>
+        power_management namespace
+      </h3></div></div></div><p>
+        Keys with the prefix <code class="literal">power_management</code>
+        provide information about power management supported by
+        the system.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">power_management.type</code> (string)
+              </td><td>Examples:
+                <code class="literal">apm</code>,
+                <code class="literal">acpi</code>,
+                <code class="literal">pmu</code>
+              </td><td>Yes</td><td>
+                The power management subsystem used on the computer.
+              </td></tr><tr><td>
+                <code class="literal">power_management.can_suspend</code> (bool)
+              </td><td> </td><td>Yes</td><td>
+                If suspend support is compiled into the kernel.
+                NB. This may not mean the machine is able to suspend
+                successfully.
+              </td></tr><tr><td>
+                <code class="literal">power_management.can_suspend_hybrid</code> (bool)
+              </td><td> </td><td>Yes</td><td>
+                If the system is capable of hybrid suspend.
+              </td></tr><tr><td>
+                <code class="literal">power_management.can_hibernate</code> (bool)
+              </td><td> </td><td>Yes</td><td>
+                If hibernation support is compiled into the kernel.
+                NB. This may not mean the machine is able to hibernate
+                successfully.
+              </td></tr><tr><td>
+                <code class="literal">power_management.is_powersave_set</code> (bool)
+              </td><td> </td><td>Yes</td><td>
+                Is the last value passed to the SetPowerSave method.
+              </td></tr><tr><td>
+                <code class="literal">power_management.quirk.s3_bios</code> (bool)
+              </td><td> </td><td>No</td><td>Use the S3_BIOS kernel command for suspend.</td></tr><tr><td>
+                <code class="literal">power_management.quirk.s3_mode</code> (bool)
+              </td><td> </td><td>No</td><td>Use the S3_MODE kernel command for suspend.</td></tr><tr><td>
+                <code class="literal">power_management.quirk.dpms_suspend</code> (bool)
+              </td><td> </td><td>No</td><td>Suspend the video card via DPMS on suspend.</td></tr><tr><td>
+                <code class="literal">power_management.quirk.vga_mode_3</code> (bool)
+              </td><td> </td><td>No</td><td>Reset the VGA text mode to mode 3 on resume.</td></tr><tr><td>
+                <code class="literal">power_management.quirk.dpms_on</code> (bool)
+              </td><td> </td><td>No</td><td>Reactivate the screen with DPMS on resume.</td></tr><tr><td>
+                <code class="literal">power_management.quirk.vbe_post</code> (bool)
+              </td><td> </td><td>No</td><td>Run the VGA BIOS Power On Self Test (POST) on resume.</td></tr><tr><td>
+                <code class="literal">power_management.quirk.vbestate_restore</code> (bool)
+              </td><td> </td><td>No</td><td>Save the VGA BIOS state before suspend, and restore it on resume.</td></tr><tr><td>
+                <code class="literal">power_management.quirk.vbemode_restore</code> (bool)
+              </td><td> </td><td>No</td><td>Save the VGA BIOS mode before suspend, and restore it on resume.</td></tr><tr><td>
+                <code class="literal">power_management.quirk.radeon_off</code> (bool)
+              </td><td> </td><td>No</td><td>Turn off the Radeon DAC off before suspend.</td></tr><tr><td>
+                <code class="literal">power_management.quirk.reset_brightness</code> (bool)
+              </td><td> </td><td>No</td><td>Reset the brightness state after resume.</td></tr><tr><td>
+                <code class="literal">power_management.quirk.no_fb</code> (bool)
+              </td><td> </td><td>No</td><td>True if the machine can only suspend when not using framebuffer.</td></tr><tr><td>
+                <code class="literal">power_management.quirk.none</code> (bool)
+              </td><td> </td><td>No</td><td>No quirks are necessary for suspend or resume.</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-tape"></a>
+        tape namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">tape</code>
+        represent tape devices.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">tape.major</code> (int)
+              </td><td>example: 254</td><td>Yes</td><td>The device's major number</td></tr><tr><td>
+                <code class="literal">tape.minor</code> (int)
+              </td><td>example: 0</td><td>Yes</td><td>The device's minor number</td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-killswitch"></a>
+        killswitch namespace
+      </h3></div></div></div><p>
+        Device objects with the capability <code class="literal">killswitch</code>
+        represent switches to turn a radio on and off. See also <a href="#interface-device-killswitch" title="org.freedesktop.Hal.Device.KillSwitch interface">the section called “org.freedesktop.Hal.Device.KillSwitch interface”</a>.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">killswitch.type</code> (string)
+              </td><td> </td><td>Yes</td><td>Type of the kill switch</td></tr><tr><td> </td><td>wlan</td><td> </td><td>Kill switch is for turning Wireless networking on/off</td></tr><tr><td> </td><td>bluetooth</td><td> </td><td>Kill switch is for turning Bluetooth on/off</td></tr><tr><td>
+                <code class="literal">killswitch.access_method</code> (string)
+              </td><td> </td><td>Yes</td><td>How HAL should program the switch</td></tr></tbody></table></div></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="properties-misc"></a>Misc. Properties</h2></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="device-properties-access-control"></a>
+        access_control namespace
+      </h3></div></div></div><p>
+        Device objects with the
+        capability <code class="literal">access_control</code> represent devices
+        where access to a special device file can be granted/revoked
+        to unprivileged users.
+      </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Values</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>
+                <code class="literal">access_control.file</code> (string)
+              </td><td>Example: /dev/snd/pcmC0D1p</td><td>Yes</td><td>
+                Name of the special device file that access can be granted to.
+              </td></tr><tr><td>
+                <code class="literal">access_control.type</code> (string)
+              </td><td>Example: cdrom</td><td>Yes</td><td>
+                Type of access - only makes sense when PolicyKit
+                support is enabled; it's used by PolicyKit to compute
+                what privilege to check for by
+                prepending <code class="literal">hal-device-file-</code> to the
+                value.
+              </td></tr><tr><td>
+                <code class="literal">access_control.grant_user</code> (strlist)
+              </td><td>Example: "gdm, flumotion"</td><td>No</td><td>
+                List of UNIX user names to always grant access to the
+                device. This is useful for 3rd party system-wide
+                packages that need access to a device to function
+                properly.
+              </td></tr><tr><td>
+                <code class="literal">access_control.grant_group</code> (strlist)
+              </td><td>Example: "pvr_software, staff"</td><td>No</td><td>
+                List of UNIX group names to always grant access to the
+                device. This is useful for 3rd party system-wide
+                packages that need access to a device to function
+                properly.
+              </td></tr></tbody></table></div><p>
+        See also <a href="#interface-device-accesscontrol" title="org.freedesktop.Hal.Device.AccessControl interface">the section called “org.freedesktop.Hal.Device.AccessControl interface”</a>.
+      </p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="properties-deprecated"></a>Deprecated Properties</h2></div></div></div><p>
+      The section represents properties that are deprecated and should be no longer used. 
+      The properties/keys will be removed, but not before the date in the following table:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Key (type)</th><th>Replacement</th><th>Remove (date)</th><th>Notes</th></tr></thead><tbody><tr><td><code class="literal">info.bus</code> (string)</td><td><code class="literal">info.subsystem</code></td><td>2008-03-01</td><td>Renamed to something more abstract, available until removed.</td></tr><tr><td><code class="literal">*.physical_device</code> (string)</td><td><code class="literal">*.originating_device</code></td><td>2008-03-01</td><td>Renamed to something more abstract, available until removed.</td></tr><tr><td><code class="literal">portable_audio_player.access_method</code> (string)</td><td><code class="literal">portable_audio_player.access_method.[drivers, protocols]</code> (strlist)</td><td>2008-05-03</td><td>Original entry can only indicate UMS or userspace driver devices, while some devices can be both.  New structure doesn't have this limitation.</td></tr><tr><td><code class="literal">portable_audio_player.type</code> (string)</td><td><code class="literal">portable_audio_player.access_method.[drivers, protocols]</code> (strlist)</td><td>2008-05-03</td><td>New structure allows for better definition of access protocols and handlers.</td></tr><tr><td><code class="literal">power_management.can_suspend_to_ram</code> (bool)</td><td><code class="literal">power_management.can_suspend</code></td><td>2007-05-01</td><td> </td></tr><tr><td><code class="literal">power_management.can_suspend_to_disk</code> (bool)</td><td><code class="literal">power_management.can_hibernate</code></td><td>2007-05-01</td><td> </td></tr><tr><td><code class="literal">smbios.system.manufacturer</code> (string)</td><td><code class="literal">system.hardware.vendor</code></td><td>2008-02-28</td><td>Renamed to something more abstract.</td></tr><tr><td><code class="literal">smbios.system.product</code> (string)</td><td><code class="literal">system.hardware.product</code></td><td>2008-02-28</td><td>Renamed to something more abstract.</td></tr><tr><td><code class="literal">smbios.system.version</code> (string)</td><td><code class="literal">system.hardware.version</code></td><td>2008-02-28</td><td>Renamed to something more abstract.</td></tr><tr><td><code class="literal">smbios.system.serial</code> (string)</td><td><code class="literal">system.hardware.serial</code></td><td>2008-02-28</td><td>Renamed to something more abstract.</td></tr><tr><td><code class="literal">smbios.system.uuid</code> (string)</td><td><code class="literal">system.hardware.uuid</code></td><td>2008-02-28</td><td>Renamed to something more abstract.</td></tr><tr><td><code class="literal">smbios.bios.vendor</code> (string)</td><td><code class="literal">system.firmware.vendor</code></td><td>2008-02-28</td><td>Renamed to something more abstract.</td></tr><tr><td><code class="literal">smbios.bios.version</code> (string)</td><td><code class="literal">system.firmware.version</code></td><td>2008-02-28</td><td>Renamed to something more abstract.</td></tr><tr><td><code class="literal">smbios.bios.release_date</code> (string)</td><td><code class="literal">system.firmware.release_date</code></td><td>2008-02-28</td><td>Renamed to something more abstract.</td></tr><tr><td><code class="literal">smbios.chassis.manufacturer</code> (string)</td><td><code class="literal">system.chassis.manufacturer</code></td><td>2008-02-28</td><td>Renamed to something more abstract.</td></tr><tr><td><code class="literal">smbios.chassis.type</code> (string)</td><td><code class="literal">system.chassis.type</code></td><td>2008-02-28</td><td>Renamed to something more abstract.</td></tr><tr><td><code class="literal">system.vendor</code> (string)</td><td><code class="literal">system.hardware.vendor</code></td><td>2008-02-28</td><td>Duplicate of system.hardware.vendor.</td></tr><tr><td><code class="literal">usb_device.speed_bcd</code> (int)</td><td><code class="literal">usb_device.speed</code> (double)</td><td>2008-03-21</td><td>changed from 'BCD with two decimals' to double</td></tr><tr><td><code class="literal">usb_device.version_bcd</code> (int)</td><td><code class="literal">usb_device.version</code> (double)</td><td>2008-03-21</td><td>changed from 'BCD with two decimals' to double</td></tr></tbody></table></div></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="interfaces"></a>Chapter 6. D-Bus interfaces</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="#interface-manager">org.freedesktop.Hal.Manager interface</a></span></dt><dt><span class="sect1"><a href="#interface-device">org.freedesktop.Hal.Device interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-systempower">org.freedesktop.Hal.Device.SystemPowerManagement interface</a></span></dt><dt><span class="sect1"><a href="#interface-cpufreq">org.freedesktop.Hal.Device.CPUFreq interface</a></span></dt><dt><span class="sect1"><a href="#interface-wakeonlan">org.freedesktop.Hal.Device.WakeOnLan interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-laptop-panel">org.freedesktop.Hal.Device.LaptopPanel interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-keyboard-backlight">org.freedesktop.Hal.Device.KeyboardBacklight interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-light-sensor">org.freedesktop.Hal.Device.LightSensor interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-storage">org.freedesktop.Hal.Device.Storage interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-volume">org.freedesktop.Hal.Device.Volume interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-volume-crypto">org.freedesktop.Hal.Device.Volume.Crypto interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-killswitch">org.freedesktop.Hal.Device.KillSwitch interface</a></span></dt><dt><span class="sect1"><a href="#interface-device-accesscontrol">org.freedesktop.Hal.Device.AccessControl interface</a></span></dt><dt><span class="sect1"><a href="#interface-singleton-addon"><code class="literal">org.freedesktop.Hal.SingletonAddon</code> interface</a></span></dt></dl></div><p>
+    All of the HAL D-Bus interfaces are introspectable using the
+    standard D-Bus introspection methods (e.g. they all implement
+    the <code class="literal">org.freedesktop.DBus.Introspectable</code>
+    interface). For example, a command like
+    </p><pre class="programlisting">
+$ dbus-send --system --print-reply --dest=org.freedesktop.Hal \
+            /org/freedesktop/Hal/devices/computer             \
+            org.freedesktop.DBus.Introspectable.Introspect
+    </pre><p>
+    will print out the introspection XML for what interfaces
+    (ie. methods and signals) the given hal device object
+    supports. For brevity, the <code class="literal">org.freedesktop.Hal</code>
+    prefix have been stripped from the exceptions listed in the
+    following sections.
+  </p><p>
+    Also note that other exceptions than the ones listed may be
+    thrown; for example
+    the <code class="literal">org.freedesktop.Hal.Device.InterfaceLocked</code>
+    exception may be thrown regardless of how the interface is
+    implemented (depending on if some other process is holding a lock
+    on the device cf. <a href="#locking" title="Chapter 4. Locking">Chapter 4, <i>Locking</i></a>); if PolicyKit support
+    is enabled,
+    the <code class="literal">org.freedesktop.Hal.Device.PermissionDeniedByPolicy</code>
+    exception may be thrown (the two first words in the exception
+    detail is resp. a) the privilege the caller didn't have; b) the
+    textual result code from PolicyKit specifying if the caller can
+    obtain the privilege) if the caller is not privileged and so on.
+  </p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="interface-manager"></a>org.freedesktop.Hal.Manager interface</h2></div></div></div><p>
+      Only the <code class="literal">/org/freedesktop/Hal/Manager</code> object
+      implements this interface. It's primarily used to discover
+      devices. The following methods are available:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method</th><th>Returns</th><th>Parameters</th><th>Throws</th><th>Description</th></tr></thead><tbody><tr><td>GetAllDevices</td><td>Objref[]</td><td> </td><td> </td><td>
+              Get all UDI's in the database.
+            </td></tr><tr><td>DeviceExists</td><td>Bool</td><td> </td><td> </td><td>
+              Determines if a given object exists.
+            </td></tr><tr><td>FindDeviceStringMatch</td><td>Objref[]</td><td>String key, String value</td><td> </td><td>
+              Find devices for which the given string property assumes the given value.
+            </td></tr><tr><td>FindDeviceByCapability</td><td>Objref[]</td><td>String capability</td><td> </td><td>
+              Finds devices of the given capability.
+            </td></tr><tr><td>NewDevice</td><td>Objref</td><td> </td><td>PermissionDenied</td><td>
+              Creates a new device object in the temporary device list
+              (TDL) and return the UDI. Caller must be uid 0.
+            </td></tr><tr><td>Remove</td><td> </td><td>Objref tmp_udi</td><td>NoSuchDevice, PermissionDenied</td><td>
+              Removes a device object that was created in the
+              TDL. Caller must be uid 0.
+            </td></tr><tr><td>CommitToGdl</td><td> </td><td>Objref tmp_udi, Objref udi</td><td>NoSuchDevice, PermissionDenied</td><td>
+              Moves a device from the temporary device list (TDL) to
+              the global device list (GDL). Caller must be uid 0.
+            </td></tr><tr><td>AcquireGlobalInterfaceLock</td><td> </td><td>String interface_name, Bool exclusive</td><td>Device.InterfaceAlreadyLocked</td><td>
+              Acquires a global lock on an interface. See
+              <a href="#locking" title="Chapter 4. Locking">Chapter 4, <i>Locking</i></a> for details.
+            </td></tr><tr><td>ReleaseGlobalInterfaceLock</td><td> </td><td>String interface_name</td><td>Device.InterfaceNotLocked</td><td>
+              Releases a global lock on an interface. See
+              <a href="#locking" title="Chapter 4. Locking">Chapter 4, <i>Locking</i></a> for details.
+            </td></tr><tr><td>SingletonAddonIsReady</td><td> </td><td>String command_line</td><td>PermissionDenied, SyntaxError</td><td>
+              Called by singleton addons to signal that they are
+              ready to handle devices.  A singleton addon should
+              implement the <a href="#interface-singleton-addon" title="org.freedesktop.Hal.SingletonAddon interface">
+                org.freedesktop.Hal.Singleton</a> interface.
+            </td></tr></tbody></table></div><p>
+      The following signals are emitted:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Signal</th><th>Parameters</th><th>Description</th></tr></thead><tbody><tr><td>DeviceAdded</td><td>Objref obj</td><td>
+              A device was added to the global device list (GDL).
+            </td></tr><tr><td>DeviceRemoved</td><td>Objref obj</td><td>
+              A device was removed from the global device list (GDL).
+            </td></tr><tr><td>NewCapability</td><td>Objref obj, String cap</td><td>
+              A device gained a new capability.
+            </td></tr><tr><td>GlobalInterfaceLockAcquired</td><td>String lock_name, String lock_owner, Int num_holders</td><td>
+              Sent when a process acquires a global interface lock.
+            </td></tr><tr><td>GlobalInterfaceLockReleased</td><td>String lock_name, String lock_owner, Int num_holders</td><td>
+              Sent when a process releases a global interface lock.
+            </td></tr></tbody></table></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="interface-device"></a>org.freedesktop.Hal.Device interface</h2></div></div></div><p>
+      Every hal device object (e.g. objects where the object path is
+      prefixed with <code class="literal">/org/freedesktop/Hal/devices/</code>)
+      implements this interface. It provides generic
+      functionality. The following methods are available:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method</th><th>Returns</th><th>Parameters</th><th>Throws</th><th>Description</th></tr></thead><tbody><tr><td>GetProperty</td><td>Variant</td><td>String key</td><td>NoSuchProperty</td><td>
+              Get property.
+            </td></tr><tr><td>GetPropertyString</td><td>String</td><td>String key</td><td>NoSuchProperty, TypeMismatch</td><td>
+              Get property.
+            </td></tr><tr><td>GetPropertyStringList</td><td>String[]</td><td>String key</td><td>NoSuchProperty, TypeMismatch</td><td>
+              Get property.
+            </td></tr><tr><td>GetPropertyInteger</td><td>Int</td><td>String key</td><td>NoSuchProperty, TypeMismatch</td><td>
+              Get property.
+            </td></tr><tr><td>GetPropertyUInt64</td><td>UInt64</td><td>String key</td><td>NoSuchProperty, TypeMismatch</td><td>
+              Get property.
+            </td></tr><tr><td>GetPropertyBoolean</td><td>Bool</td><td>String key</td><td>NoSuchProperty, TypeMismatch</td><td>
+              Get property.
+            </td></tr><tr><td>GetPropertyDouble</td><td>Double</td><td>String key</td><td>NoSuchProperty, TypeMismatch</td><td>
+              Get property.
+            </td></tr><tr><td>SetProperty</td><td>Variant</td><td>String key</td><td>PermissionDenied</td><td>
+              Set property.
+            </td></tr><tr><td>SetPropertyString</td><td>String</td><td>String key</td><td>PermissionDenied, TypeMismatch</td><td>
+              Set property.
+            </td></tr><tr><td>SetPropertyStringList</td><td>String[]</td><td>String key</td><td>PermissionDenied, TypeMismatch</td><td>
+              Set property.
+            </td></tr><tr><td>SetPropertyInteger</td><td>Int</td><td>String key</td><td>PermissionDenied, TypeMismatch</td><td>
+              Set property.
+            </td></tr><tr><td>SetPropertyUInt64</td><td>UInt64</td><td>String key</td><td>PermissionDenied, TypeMismatch</td><td>
+              Set property.
+            </td></tr><tr><td>SetPropertyBoolean</td><td>Bool</td><td>String key</td><td>PermissionDenied, TypeMismatch</td><td>
+              Set property.
+            </td></tr><tr><td>SetPropertyDouble</td><td>Double</td><td>String key</td><td>PermissionDenied, TypeMismatch</td><td>
+              Set property.
+            </td></tr><tr><td>RemoveProperty</td><td> </td><td>String key</td><td>NoSuchProperty, PermissionDenied</td><td>
+              Remove a property.
+            </td></tr><tr><td>GetPropertyType</td><td>Int</td><td>String key</td><td>NoSuchProperty</td><td>
+              Get the type of a property. Returns the D-Bus type as an integer.
+            </td></tr><tr><td>PropertyExists</td><td>Bool</td><td>String key</td><td> </td><td>
+              Determine if a property exists.
+            </td></tr><tr><td>AddCapability</td><td> </td><td>String capability</td><td>PermissionDenied</td><td>
+              Adds a capability to a device.
+            </td></tr><tr><td>QueryCapability</td><td>Bool</td><td>String capability</td><td> </td><td>
+              Determine if a device have a capability.
+            </td></tr><tr><td>Lock</td><td>Bool</td><td>String reason</td><td>DeviceAlreadyLocked</td><td>
+              Acquires an advisory lock on the device. Returns TRUE if the lock was acquired.
+            </td></tr><tr><td>Unlock</td><td>Bool</td><td> </td><td>DeviceNotLocked</td><td>
+              Releases an advisory lock on the device. Returns TRUE if the lock was released.
+            </td></tr><tr><td>AcquireInterfaceLock</td><td> </td><td>String interface_name, Bool exclusive</td><td>PermissionDenied, Device.InterfaceAlreadyLocked</td><td>
+              Acquires a lock on an interface for a specific
+              device. See <a href="#locking" title="Chapter 4. Locking">Chapter 4, <i>Locking</i></a> for details.
+            </td></tr><tr><td>ReleaseInterfaceLock</td><td> </td><td>String interface_name</td><td>PermissionDenied, Device.InterfaceNotLocked</td><td>
+              Releases a lock on an interface for a specific device. See
+              <a href="#locking" title="Chapter 4. Locking">Chapter 4, <i>Locking</i></a> for details.
+            </td></tr><tr><td>IsCallerLockedOut</td><td>Bool</td><td>String interface_name, String caller_unique_name</td><td>PermissionDenied</td><td>
+              Determines whether a given process on the system message
+              bus is locked out from an interface on a specific
+              device. Only HAL helpers are privileged to use this
+              method. See <a href="#locking" title="Chapter 4. Locking">Chapter 4, <i>Locking</i></a> for details.
+            </td></tr><tr><td>IsCallerPrivileged</td><td>String</td><td>String privilege, String caller_unique_name</td><td>PermissionDenied, Error</td><td>
+              <p>
+                Determines whether a given process on the system
+                message bus is authorized according to PolicyKit on a
+                specific device for a specific PolicyKit
+                privilege. Unprivileged callers (e.g. with a non-zero
+                uid) can only ask
+                about <code class="literal">caller_unique_name</code> that
+                matches their own uid; if this is violated
+                <code class="literal">PermissionDenied</code> will be
+                thrown. This can be used ahead of time to see if a
+                given call will succeed or if it requires privilege
+                elevation (TODO: clarify this once PolicyKit can auth
+                over D-Bus).
+              </p>
+              <p>
+                Returns the textual representation of a PolKitResult
+                value on success. 
+              </p>
+              <p>
+                If HAL is not built with PolicyKit support, this
+                method always throws
+                the <code class="literal">org.freedesktop.Hal.Device.Error</code>
+                exception.
+              </p>
+            </td></tr><tr><td>IsLockedByOthers</td><td>Bool</td><td>String interface_name</td><td> </td><td>
+              Determines whether a determines other processes than the
+              caller holds a lock on the given device. See
+              <a href="#locking" title="Chapter 4. Locking">Chapter 4, <i>Locking</i></a> for details.
+            </td></tr><tr><td>StringListAppend</td><td> </td><td>String key, String value</td><td>PermissionDenied, TypeMismatch</td><td>
+              Appends an item to a string list.
+            </td></tr><tr><td>StringListPrepend</td><td> </td><td>String key, String value</td><td>PermissionDenied, TypeMismatch</td><td>
+              Prepends an item to a string list.
+            </td></tr><tr><td>StringListRemove</td><td> </td><td>String key, String value</td><td>PermissionDenied, TypeMismatch</td><td>
+              Removes an item from a string list.
+            </td></tr><tr><td>EmitCondition</td><td>Bool</td><td>String name, String details</td><td>PermissionDenied</td><td>
+              Emit a condition on a device object.
+            </td></tr><tr><td>Rescan</td><td>Bool</td><td> </td><td>PermissionDenied</td><td>
+              Force an updates of the properties of a device object by
+              rereading data that is not monitored for changes.
+            </td></tr><tr><td>Reprobe</td><td>Bool</td><td> </td><td>PermissionDenied</td><td>
+              Cause a synthetic remove and subsequent add of the given
+              device object including all children beneath it. Will
+              generate at least one pair of DeviceRemoved() and
+              DeviceAdded() signals on the Manager interface.
+            </td></tr><tr><td>ClaimInterface</td><td>Bool</td><td>String name, String introspection_xml</td><td>PermissionDenied</td><td>
+              An addon can use this method for making the HAL daemon
+              route all D-Bus calls on the given interface to the
+              addon via the peer to peer D-Bus connection between the
+              addon and the HAL daemon.
+            </td></tr><tr><td>AddonIsReady</td><td>Bool</td><td> </td><td>PermissionDenied</td><td>
+              An addon needs to call this method when it's ready for
+              the device to be announced on D-Bus. The rationale for
+              this method is to allow an addon to modify the device
+              object and claim interfaces before the device is
+              announced on D-Bus.
+            </td></tr></tbody></table></div><p>
+      The following signals are emitted:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Signal</th><th>Parameters</th><th>Description</th></tr></thead><tbody><tr><td>PropertyModified</td><td>Int num_changes, Array of struct {String property_name, Bool added, Bool removed}</td><td>
+              One or more properties on the device object have changed.
+            </td></tr><tr><td>Condition</td><td>String name, String details</td><td>
+              A generic mechanism used to specify a device condition
+              that cannot be expressed in device properties. (NOTE:
+              newly written code should use dedicated signals on a
+              dedicated interface.).
+            </td></tr><tr><td>InterfaceLockAcquired</td><td>String lock_name, String lock_owner, Int num_holders</td><td>
+              Sent when a process acquires an interface lock on the device.
+            </td></tr><tr><td>InterfaceLockReleased</td><td>String lock_name, String lock_owner, Int num_holders</td><td>
+              Sent when a process releases an interface lock on the device.
+            </td></tr></tbody></table></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="interface-device-systempower"></a>org.freedesktop.Hal.Device.SystemPowerManagement interface</h2></div></div></div><p>
+      This interface provides a mechanism to affect system-wide power
+      management. Normally only the root computer device object
+      (<code class="literal">/org/freedesktop/Hal/devices/computer</code>)
+      implements this interface. The following methods are available:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method</th><th>Returns</th><th>Parameters</th><th>Throws</th><th>Description</th></tr></thead><tbody><tr><td>Suspend</td><td>Int</td><td>Int num_secs_to_wakeup</td><td>SystemPowerManagement.NotSupported, SystemPowerManagement.AlarmNotSupported</td><td>
+              Puts the system in a suspended state (typically ACPI S3)
+              for <code class="literal">num_secs_to_wakeup</code> seconds. If
+              the given time is zero, the system is put in the
+              suspended state indefinitely. If wake-up isn't supported
+              the the AlarmNotSupported exception is thrown. Latency
+              for the system to return to an operational state is in
+              the order of magnitude of 5 seconds.
+            </td></tr><tr><td>Hibernate</td><td>Int</td><td> </td><td>SystemPowerManagement.NotSupported</td><td>
+              Save system state to persistent storage and power off
+              the system (typically ACPI S4). Latency for the system
+              to return to an operational state is in the order of
+              magnitude of one minute.
+            </td></tr><tr><td>SuspendHybrid</td><td>Int</td><td>Int num_secs_to_wakeup</td><td>SystemPowerManagement.NotSupported, SystemPowerManagement.AlarmNotSupported</td><td>
+              Puts the system in a suspended state (typically ACPI S3)
+              for <code class="literal">num_secs_to_wakeup</code> seconds but
+              also write the system state to persistent storage so the
+              system can resume even if power is removed. Like with
+              Suspend(), if the given time is zero, the system is put
+              in the suspended state indefinitely. If wake-up isn't
+              supported the the AlarmNotSupported exception is thrown.
+            </td></tr><tr><td>Shutdown</td><td>Int</td><td> </td><td>SystemPowerManagement.NotSupported</td><td>
+              Shut down the system.
+            </td></tr><tr><td>Reboot</td><td>Int</td><td> </td><td>SystemPowerManagement.NotSupported</td><td>
+              Reboot the system.
+            </td></tr><tr><td>SetPowerSave</td><td>Int</td><td>Bool should_save_power</td><td>SystemPowerManagement.NotSupported</td><td>
+              If the boolean passed is TRUE, the system will be
+              configured to save as much power as possible by
+              e.g. enabling <code class="literal">laptop mode</code> to avoid
+              spinning up disks. Typically, power management daemons
+              will call this method when it determines that the system
+              is running on battery power.
+            </td></tr></tbody></table></div><p>
+      This interface does not emit any signals.
+    </p><p>
+      Implementors of power management daemons should make sure that
+      their software respects the locking guidelines described in
+      <a href="#interfaces" title="Chapter 6. D-Bus interfaces">Chapter 6, <i>D-Bus interfaces</i></a>.
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="interface-cpufreq"></a>org.freedesktop.Hal.Device.CPUFreq interface</h2></div></div></div><p>
+      This interface provides a mechanism to configure CPU frequency
+      scaling. The following methods are available:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method</th><th>Returns</th><th>Parameters</th><th>Throws</th><th>Description</th></tr></thead><tbody><tr><td>GetCPUFreqAvailableGovernors</td><td>String[]</td><td> </td><td> </td><td>
+              Retrieves a list of available CPU scaling governors.
+            </td></tr><tr><td>GetCPUFreqGovernor</td><td>String</td><td> </td><td> </td><td>
+              Get currently selected CPU Frequency governor.
+            </td></tr><tr><td>SetCPUFreqGovernor</td><td>Void</td><td>String governor</td><td>CPUFreq.UnknownGovernor</td><td>
+              Selects a CPU frequency scaling governor for all CPUFreq
+             interfaces the kernel provides. If the userspace governor is
+             set, this interface also contains a proper scaling
+             mechanism.
+            </td></tr><tr><td>SetCPUFreqPerformance</td><td>Void</td><td>Int (1 to 100)</td><td>CPUFreq.NoSuitableGovernor</td><td>
+              Sets the performance of the dynamic scaling
+              mechanism. This method summarizes and abstracts all the
+              different settings which can be taken for dynamic
+              frequency adjustments, like at which load to switch up
+              frequency or how many steps the mechanism should
+              traverse until reaching the maximum frequency. The
+              higher the value, the more performance you
+              get. Respectively, the higher the value, the sooner and
+              the more often the frequency is switched up.
+            </td></tr><tr><td>GetCPUFreqPerformance</td><td>Int</td><td> </td><td>CPUFreq.NoSuitableGovernor</td><td>
+              Get the tuning value for the governor.
+            </td></tr><tr><td>SetCPUFreqConsiderNice</td><td>Void</td><td>Bool consider_niced_processes</td><td>CPUFreq.NoSuitableGovernor</td><td>
+              Whether or not niced processes should be considered on
+              CPU load calculation. If niced processes are considered,
+              they can cause a frequency increment although their
+              absolute load percentage wouldn't trigger the scaling
+              mechanism to switch up the frequency. The default
+              setting is 'false'.
+            </td></tr><tr><td>GetCPUFreqConsiderNice</td><td>Bool</td><td> </td><td>CPUFreq.NoSuitableGovernor</td><td>
+              Whether nice'ed processes are considered by the governor.
+            </td></tr></tbody></table></div><p>
+      This interface does not emit any signals.
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="interface-wakeonlan"></a>org.freedesktop.Hal.Device.WakeOnLan interface</h2></div></div></div><p>
+      This interface provides a mechanism to configure Wake On LAN
+      capabilities. The following methods are available:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method</th><th>Returns</th><th>Parameters</th><th>Throws</th><th>Description</th></tr></thead><tbody><tr><td>GetSupported</td><td>Bool</td><td> </td><td>WakeOnLan.NoEthtool</td><td>
+             Get if device supports Wake On LAN 
+            </td></tr><tr><td>GetEnabled</td><td>Bool</td><td> </td><td>WakeOnLan.NoEthtool</td><td>
+              Get if Wake On LAN is enabled
+            </td></tr><tr><td>SetEnabled</td><td>Void</td><td>Bool</td><td>WakeOnLan.NoEthtool</td><td>
+             Enable or disable Wake On LAN
+            </td></tr></tbody></table></div><p>
+      This interface does not emit any signals.
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="interface-device-laptop-panel"></a>org.freedesktop.Hal.Device.LaptopPanel interface</h2></div></div></div><p>
+      This interface provides a mechanism to get/set the brightness of
+      a laptop panel. The following methods are available:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method</th><th>Returns</th><th>Parameters</th><th>Throws</th><th>Description</th></tr></thead><tbody><tr><td>GetBrightness</td><td>Int</td><td> </td><td> </td><td>
+              Get the current brightness.
+            </td></tr><tr><td>SetBrightness</td><td> </td><td>Int brightness</td><td> </td><td>
+              Set the current brightness.
+            </td></tr></tbody></table></div><p>
+      This interface does not emit any signals.
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="interface-device-keyboard-backlight"></a>org.freedesktop.Hal.Device.KeyboardBacklight interface</h2></div></div></div><p>
+      This interface provides a mechanism to get/set the brightness of
+      the keyboard backlight. The following methods are available:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method</th><th>Returns</th><th>Parameters</th><th>Throws</th><th>Description</th></tr></thead><tbody><tr><td>GetBrightness</td><td>Int</td><td> </td><td> </td><td>
+              Get the current brightness.
+            </td></tr><tr><td>SetBrightness</td><td> </td><td>Int brightness</td><td> </td><td>
+              Set the current brightness.
+            </td></tr></tbody></table></div><p>
+      This interface does not emit any signals.
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="interface-device-light-sensor"></a>org.freedesktop.Hal.Device.LightSensor interface</h2></div></div></div><p>
+      This interface provides a mechanism to get information from a
+      light sensor. The following methods are available:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method</th><th>Returns</th><th>Parameters</th><th>Throws</th><th>Description</th></tr></thead><tbody><tr><td>GetBrightness</td><td>Int[]</td><td> </td><td> </td><td>
+              The current brightness as measured by the light sensor.
+            </td></tr></tbody></table></div><p>
+      This interface does not emit any signals.
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="interface-device-storage"></a>org.freedesktop.Hal.Device.Storage interface</h2></div></div></div><p>
+      This interface provides a mechanism to interact with a storage
+      device. The following methods are available:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method</th><th>Returns</th><th>Parameters</th><th>Throws</th><th>Description</th></tr></thead><tbody><tr><td>Eject</td><td>Int</td><td>String[] options</td><td>Volume.PermissionDenied, Volume.NotMounted, Volume.NotMountedByHal, Volume.Busy, Volume.InvalidEjectOption</td><td>
+              Unmounts all volumes and possibly ejects the media. Note
+              that this method is not only restricted to optical
+              drives.
+            </td></tr><tr><td>CloseTray</td><td>Int</td><td>String[] options</td><td>Storage.InvalidCloseTrayOption</td><td>
+              Attempts to close the tray. Only really makes sense for
+              (optical) drives that uses a tray loading mechanism.
+            </td></tr></tbody></table></div><p>
+      This interface does not emit any signals.
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="interface-device-volume"></a>org.freedesktop.Hal.Device.Volume interface</h2></div></div></div><p>
+      This interface provides a mechanism to interact with a volume
+      that has a mountable file system. The following methods are
+      available:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method</th><th>Returns</th><th>Parameters</th><th>Throws</th><th>Description</th></tr></thead><tbody><tr><td>Mount</td><td>Int</td><td>String mount_point, String fstype, String[] options</td><td>Volume.PermissionDenied, Volume.AlreadyMounted, Volume.InvalidMountOption, Volume.UnknownFilesystemType, Volume.InvalidMountPoint, Volume.MountPointNotAvailable, Volume.CannotRemount</td><td>
+              Mounts a volume.
+            </td></tr><tr><td>Unmount</td><td>Int</td><td>String[] options</td><td>Volume.PermissionDenied, Volume.NotMounted, Volume.NotMountedByHal, Volume.Busy, Volume.InvalidUnmountOption</td><td>
+              Unmount a volume.
+            </td></tr><tr><td>Eject</td><td>Int</td><td>String[] options</td><td>Volume.PermissionDenied, Volume.NotMounted, Volume.NotMountedByHal, Volume.Busy, Volume.InvalidEjectOption</td><td>
+              Unmounts all volumes from the originating drive and
+              possibly ejects the media. Note that this method is not
+              only restricted to optical drives.
+            </td></tr></tbody></table></div><p>
+      This interface does not emit any signals.
+    </p><p>
+      If a volume originates from a storage device (and all volumes
+      do), it also is checked whether the caller is locked out of the
+      <code class="literal">org.freedesktop.Hal.Device.Storage</code> interface
+      of the originating storage device. As a corollary, it is
+      sufficient to just either a) lock the storage device; or b)
+      globally lock
+      the <code class="literal">org.freedesktop.Hal.Device.Storage</code>
+      interface if one wants to lock out callers from mounting
+      volumes from either a specific drive or all drives.
+
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="interface-device-volume-crypto"></a>org.freedesktop.Hal.Device.Volume.Crypto interface</h2></div></div></div><p>
+      This interface provides a mechanism to interact with a volume that
+      is encrypted at the block layer. The following methods are
+      available:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method</th><th>Returns</th><th>Parameters</th><th>Throws</th><th>Description</th></tr></thead><tbody><tr><td>Setup</td><td>Int</td><td>String passphrase</td><td>Volume.Crypto.CryptSetupMissing, Volume.Crypto.SetupError, Volume.Crypto.SetupPasswordError</td><td>
+              Unlocks an encrypted file system. If successful, a cleartext volume will appear.
+            </td></tr><tr><td>Teardown</td><td>Int</td><td> </td><td>Volume.Crypto.TeardownError</td><td>
+              Teardown the cleartext volume.
+            </td></tr></tbody></table></div><p>
+      This interface does not emit any signals.
+    </p><p>
+      For objects implementing this interface, it will also be checked
+      if the caller is locked out of the Volume interface on the
+      device (and per <a href="#interface-device-volume" title="org.freedesktop.Hal.Device.Volume interface">the section called “org.freedesktop.Hal.Device.Volume interface”</a> this
+      includes checking whether the caller is locked out of
+      the <code class="literal">org.freedesktop.Hal.Device.Storage</code>
+      interface for the storage device that the volume originates
+      from).
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="interface-device-killswitch"></a>org.freedesktop.Hal.Device.KillSwitch interface</h2></div></div></div><p>
+      This interface provides a mechanism for both querying whether a
+      radio is on as well as turning it on and off.  The following
+      methods are available:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method</th><th>Returns</th><th>Parameters</th><th>Throws</th><th>Description</th></tr></thead><tbody><tr><td>GetPower</td><td>Int</td><td> </td><td> </td><td>
+              Returns 1 if, and only if, the power is on.
+            </td></tr><tr><td>SetPower</td><td> </td><td>Bool</td><td> </td><td>
+              Set the power of the radio.
+            </td></tr></tbody></table></div><p>
+      This interface does not emit any signals.
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="interface-device-accesscontrol"></a>org.freedesktop.Hal.Device.AccessControl interface</h2></div></div></div><p>
+      This interface provides a mechanism for discovering when an ACL
+      is added or removed for a device file. The following signals are
+      available:
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method</th><th>Parameters</th><th>Description</th></tr></thead><tbody><tr><td>ACLAdded</td><td>UInt unix_user_id</td><td>
+              Emitted when an ACL have been added for a UNIX user on a
+              device object with the <code class="literal">access_control</code>
+              capability.
+            </td></tr><tr><td>ACLRemoved</td><td>UInt unix_user_id</td><td>
+              Emitted when an ACL have been removed for a UNIX user on
+              a device object with
+              the <code class="literal">access_control</code> capability.
+            </td></tr></tbody></table></div><p>
+      This interface does not export any methods.
+    </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="interface-singleton-addon"></a><code class="literal">org.freedesktop.Hal.SingletonAddon</code> interface</h2></div></div></div><p>
+      This interface is provided by singleton addons to allow the Manager to
+      request handling of new devices and removal of old ones.
+
+      This differs from other HAL interface definitions in that it
+      is provided by addon processes, rather than the HAL daemon itself.
+
+      It should be exported on the path
+      <code class="literal">/org/freedesktop/Hal/Manager</code>.
+    </p><div class="informaltable"><table border="1"><colgroup><col><col></colgroup><thead><tr><th>Method</th><th>Returns</th><th>Parameters</th><th>Throws</th><th>Description</th></tr></thead><tbody><tr><td>
+              <code class="literal">DeviceAdded</code>
+            </td><td>
+              <p><code class="literal">String udi</code></p>
+              <p><code class="literal">Dict(String,Variant) property_set</code></p>
+            </td><td> </td><td> </td><td>
+              <p>
+                Called by the HAL Manager when a device is added that has
+                this singleton listed in
+                <a href="#device-properties-info-singleton-addons" title="Singleton Addons">
+                  <code class="literal">info.addons.singleton</code>
+                </a>
+              </p>
+              <p>
+                An addon implementing this function should start handling the
+                device before returning, and keep track that is is handling this
+                udi.
+              </p>
+            </td></tr><tr><td>
+              <code class="literal">DeviceRemoved</code>
+            </td><td>
+              <p><code class="literal">String udi</code></p>
+              <p><code class="literal">Dict(String,Variant) property_set</code></p>
+            </td><td> </td><td> </td><td>
+              <p>
+                Called by the HAL Manager when a device is added that has
+                this singleton listed in
+                <a href="#device-properties-info-singleton-addons" title="Singleton Addons">
+                  <code class="literal">info.addons.singleton</code>
+                </a>
+              </p>
+              <p>
+                The implementer of this function should keep track of
+                which devices it is still handling and exit when no longer
+                handling any devices.
+              </p>
+            </td></tr></tbody></table></div><p>
+      This interface does not export any methods.
+    </p></div></div></div></body></html>
diff --git a/src/lib/hal/Makefile.am b/src/lib/hal/Makefile.am
new file mode 100644 (file)
index 0000000..405ac3e
--- /dev/null
@@ -0,0 +1,22 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I $(top_srcdir)/src/lib/dbus \
+@EDBUS_CFLAGS@
+
+lib_LTLIBRARIES = libehal.la
+includes_HEADERS = E_Hal.h
+includesdir = $(includedir)/e_dbus-@VMAJ@
+
+libehal_la_SOURCES = \
+e_hal_device.c  \
+e_hal_manager.c \
+e_hal_util.c \
+e_hal_main.c
+
+libehal_la_LIBADD = \
+@EDBUS_LIBS@ $(top_builddir)/src/lib/dbus/libedbus.la
+
+libehal_la_LDFLAGS = -version-info @version_info@ @release_info@
+
+EXTRA_DIST = e_hal_private.h
diff --git a/src/lib/hal/e_hal_device.c b/src/lib/hal/e_hal_device.c
new file mode 100644 (file)
index 0000000..79604e6
--- /dev/null
@@ -0,0 +1,383 @@
+#include <stdlib.h>
+
+#include <E_Hal.h>
+#include "e_hal_private.h"
+
+#define e_hal_device_call_new(udi, member) dbus_message_new_method_call(E_HAL_SENDER, udi, E_HAL_DEVICE_INTERFACE, member)
+#define e_hal_device_volume_call_new(udi, member) dbus_message_new_method_call(E_HAL_SENDER, udi, E_HAL_DEVICE_VOLUME_INTERFACE, member)
+
+#if 0
+static void cb_device_get_property(void *data, DBusMessage *msg, DBusError *err);
+static void cb_device_get_all_properties(void *data, DBusMessage *msg, DBusError *err);
+static void cb_device_query_capability(void *data, DBusMessage *msg, DBusError *err);
+#endif
+
+/* Device.GetProperty */
+static void *
+unmarshal_device_get_property(DBusMessage *msg, DBusError *err)
+{
+  E_Hal_Device_Get_Property_Return *ret = NULL;
+  DBusMessageIter iter;
+  int type;
+  const char *str;
+
+  ret = calloc(1, sizeof(E_Hal_Device_Get_Property_Return));
+  if (!ret) 
+  {
+    dbus_set_error(err, DBUS_ERROR_NO_MEMORY, "");
+    return NULL;
+  }
+
+  dbus_message_iter_init(msg, &iter);
+  type = dbus_message_iter_get_arg_type(&iter);
+  switch(type)
+  {
+    case DBUS_TYPE_STRING:
+      ret->type = E_HAL_PROPERTY_TYPE_STRING;
+      dbus_message_iter_get_basic(&iter, &str);
+      ret->val.s = eina_stringshare_add(str);
+      break;
+    case DBUS_TYPE_INT32:
+      ret->type = E_HAL_PROPERTY_TYPE_INT;
+      dbus_message_iter_get_basic(&iter, &(ret->val.i));
+      break;
+    case DBUS_TYPE_BOOLEAN:
+      ret->type = E_HAL_PROPERTY_TYPE_BOOL;
+      dbus_message_iter_get_basic(&iter, &(ret->val.b));
+      break;
+    case DBUS_TYPE_DOUBLE:
+      ret->type = E_HAL_PROPERTY_TYPE_DOUBLE;
+      dbus_message_iter_get_basic(&iter, &(ret->val.d));
+      break;
+  }
+
+  return ret;
+}
+
+static void 
+free_device_get_property(void *data)
+{
+  E_Hal_Device_Get_Property_Return *ret = data;
+
+  if (!ret) return;
+  if (ret->type == E_HAL_PROPERTY_TYPE_STRLIST)
+  {
+    const char *str;
+    EINA_LIST_FREE(ret->val.strlist, str)
+      eina_stringshare_del(str);
+  }
+  else if (ret->type == E_HAL_PROPERTY_TYPE_STRING)
+    eina_stringshare_del(ret->val.s);
+  free(ret);
+}
+
+EAPI DBusPendingCall *
+e_hal_device_get_property(E_DBus_Connection *conn, const char *udi, const char *property, E_DBus_Callback_Func cb_func, void *data)
+{
+  DBusMessage *msg;
+  DBusPendingCall *ret;
+
+  msg = e_hal_device_call_new(udi, "GetProperty");
+  dbus_message_append_args(msg, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID);
+  ret = e_dbus_method_call_send(conn, msg, unmarshal_device_get_property, cb_func, free_device_get_property, -1, data);
+  dbus_message_unref(msg);
+  return ret;
+}
+
+/* Device.GetAllProperties */
+
+static void *
+unmarshal_device_get_all_properties(DBusMessage *msg, DBusError *err)
+{
+  E_Hal_Device_Get_All_Properties_Return *ret = NULL;
+  DBusMessageIter iter, a_iter, s_iter, v_iter;
+
+  /* a{sv} = array of string+variant */
+  if (!dbus_message_has_signature(msg, "a{sv}")) 
+  {
+    dbus_set_error(err, DBUS_ERROR_INVALID_SIGNATURE, "");
+    return NULL;
+  }
+
+  ret = calloc(1, sizeof(E_Hal_Device_Get_All_Properties_Return));
+  if (!ret) 
+  {
+    dbus_set_error(err, DBUS_ERROR_NO_MEMORY, "");
+    return NULL;
+  }
+
+  ret->properties = eina_hash_string_small_new(EINA_FREE_CB(e_hal_property_free));
+
+  dbus_message_iter_init(msg, &iter);
+  dbus_message_iter_recurse(&iter, &a_iter);
+  while (dbus_message_iter_get_arg_type(&a_iter) != DBUS_TYPE_INVALID)
+  {
+    const char *name;
+    const char *str;
+    E_Hal_Property *prop = calloc(1, sizeof(E_Hal_Property));
+    dbus_message_iter_recurse(&a_iter, &s_iter);
+    dbus_message_iter_get_basic(&s_iter, &name);
+    dbus_message_iter_next(&s_iter);
+    dbus_message_iter_recurse(&s_iter, &v_iter);
+    
+    switch(dbus_message_iter_get_arg_type(&v_iter))
+    {
+      case DBUS_TYPE_STRING:
+        prop->type = E_HAL_PROPERTY_TYPE_STRING;
+        dbus_message_iter_get_basic(&v_iter, &str);
+        prop->val.s = eina_stringshare_add(str);
+        break;
+      case DBUS_TYPE_INT32:
+        prop->type = E_HAL_PROPERTY_TYPE_INT;
+        dbus_message_iter_get_basic(&v_iter, &(prop->val.i));
+        break;
+      case DBUS_TYPE_UINT64:
+        prop->type = E_HAL_PROPERTY_TYPE_UINT64;
+        dbus_message_iter_get_basic(&v_iter, &(prop->val.u64));
+        break;
+      case DBUS_TYPE_BOOLEAN:
+        prop->type = E_HAL_PROPERTY_TYPE_BOOL;
+        dbus_message_iter_get_basic(&v_iter, &(prop->val.b));
+        break;
+      case DBUS_TYPE_DOUBLE:
+        prop->type = E_HAL_PROPERTY_TYPE_DOUBLE;
+        dbus_message_iter_get_basic(&v_iter, &(prop->val.d));
+        break;
+      case DBUS_TYPE_ARRAY:
+        prop->type = E_HAL_PROPERTY_TYPE_STRLIST;
+        {
+          DBusMessageIter list_iter;
+          prop->val.strlist = NULL;
+          dbus_message_iter_recurse(&v_iter, &list_iter);
+          while (dbus_message_iter_get_arg_type(&list_iter) != DBUS_TYPE_INVALID)
+          {
+            dbus_message_iter_get_basic(&list_iter, &str);
+            prop->val.strlist = eina_list_append(prop->val.strlist, eina_stringshare_add(str));
+            dbus_message_iter_next(&list_iter);
+          }
+        }
+        break;
+      default:
+        WARN("Ehal Error: unexpected property type (%s): %c", name, dbus_message_iter_get_arg_type(&v_iter));
+        break;
+    }
+    eina_hash_add(ret->properties, name, prop);
+
+    dbus_message_iter_next(&a_iter);
+  }
+
+  return ret;
+}
+
+static void
+free_device_get_all_properties(void *data)
+{
+  E_Hal_Device_Get_All_Properties_Return *ret = data;
+
+  if (!ret) return;
+  eina_hash_free(ret->properties);
+  free(ret);
+}
+
+EAPI DBusPendingCall *
+e_hal_device_get_all_properties(E_DBus_Connection *conn, const char *udi, E_DBus_Callback_Func cb_func, void *data)
+{
+  DBusMessage *msg;
+  DBusPendingCall *ret;
+
+  msg = e_hal_device_call_new(udi, "GetAllProperties");
+  ret = e_dbus_method_call_send(conn, msg, unmarshal_device_get_all_properties, cb_func, free_device_get_all_properties, -1, data);
+  dbus_message_unref(msg);
+  return ret;
+}
+
+
+
+/* bool Device.QueryCapability(string udi) */
+
+// XXX this is same as Device_Exists in manager.
+static void *
+unmarshal_device_query_capability(DBusMessage *msg, DBusError *err)
+{
+  E_Hal_Device_Query_Capability_Return *ret = NULL;
+  dbus_bool_t val;
+
+  ret = calloc(1, sizeof(E_Hal_Manager_Device_Exists_Return));
+  if (!ret) 
+  {
+    dbus_set_error(err, DBUS_ERROR_NO_MEMORY, "");
+    return NULL;
+  }
+
+  dbus_message_get_args(msg, err, DBUS_TYPE_BOOLEAN, &val, DBUS_TYPE_INVALID);
+
+  if (dbus_error_is_set(err))
+  {
+    free(ret);
+    return NULL;
+  }
+
+  ret->boolean = val;
+  return ret;
+}
+
+static void
+free_device_query_capability(void *data)
+{
+  E_Hal_Device_Query_Capability_Return *ret = data;
+
+  if (!ret) return;
+  free(ret);
+}
+
+EAPI DBusPendingCall *
+e_hal_device_query_capability(E_DBus_Connection *conn, const char *udi, const char *capability, E_DBus_Callback_Func cb_func, void *data)
+{
+  DBusMessage *msg;
+  DBusPendingCall *ret;
+
+  msg = e_hal_device_call_new(udi, "QueryCapability");
+  dbus_message_append_args(msg, DBUS_TYPE_STRING, &capability, DBUS_TYPE_INVALID);
+  ret = e_dbus_method_call_send(conn, msg, unmarshal_device_query_capability, cb_func, free_device_query_capability, -1, data);
+  dbus_message_unref(msg);
+  return ret;
+}
+
+
+
+/* void Device.Mount(string mount_point, string fstype, array{string}options) */
+
+/**
+ * @brief Mount a Volume
+ *
+ * @param conn the E_DBus_Connection
+ * @param udi the udi of the device object
+ * @param mount_point the path to mount to, or null for default
+ * @param fstype the fstype of the device (e.g. volume.fstype property)
+ * @param options a list of additional options (not sure... fstype dependent?)
+ * @param cb_func an optional callback to call when the mount is done
+ * @param data custom data pointer for the callback function
+ */
+EAPI DBusPendingCall *
+e_hal_device_volume_mount(E_DBus_Connection *conn, const char *udi, const char *mount_point, const char *fstype, Eina_List *options, E_DBus_Callback_Func cb_func, void *data)
+{
+  DBusMessage *msg;
+  DBusMessageIter iter, subiter;
+  Eina_List *l;
+  DBusPendingCall *ret;
+
+  msg = e_hal_device_volume_call_new(udi, "Mount");
+
+  dbus_message_iter_init_append(msg, &iter);
+  dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &mount_point);
+  dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &fstype);
+  if (dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &subiter))
+  {
+    if (options)
+    {
+      const char *opt;
+       
+      EINA_LIST_FOREACH(options, l, opt)
+      {
+        dbus_message_iter_append_basic(&subiter, DBUS_TYPE_STRING, &opt);
+      }
+    }
+    dbus_message_iter_close_container(&iter, &subiter);
+  }
+  else
+  {
+    ERR("dbus_message_iter_open_container() failed");
+  }
+
+  ret = e_dbus_method_call_send(conn, msg, NULL, cb_func, NULL, -1, data);
+  dbus_message_unref(msg);
+  return ret;
+}
+
+/* void Unmount(array{string} options) */
+
+/**
+ * @brief Unmount a Volume
+ *
+ * @param conn the E_DBus_Connection
+ * @param udi the udi of the device object
+ * @param options a list of additional options (not sure... fstype dependent?)
+ * @param cb_func an optional callback to call when the unmount is done
+ * @param data cuatom data pointer for the callback function
+ */
+EAPI DBusPendingCall *
+e_hal_device_volume_unmount(E_DBus_Connection *conn, const char *udi, Eina_List *options, E_DBus_Callback_Func cb_func, void *data)
+{
+  DBusMessage *msg;
+  DBusMessageIter iter, subiter;
+  Eina_List *l;
+  DBusPendingCall *ret;
+
+  msg = e_hal_device_volume_call_new(udi, "Unmount");
+
+  dbus_message_iter_init_append(msg, &iter);
+  if (dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &subiter))
+  {
+    if (options)
+    {
+      const char *opt;
+       
+      EINA_LIST_FOREACH(options, l, opt)
+      {
+        dbus_message_iter_append_basic(&subiter, DBUS_TYPE_STRING, &opt);
+      }
+    }
+    dbus_message_iter_close_container(&iter, &subiter);
+  }
+  else
+  {
+    ERR("dbus_message_iter_open_container() failed");
+  }
+
+  ret = e_dbus_method_call_send(conn, msg, NULL, cb_func, NULL, -1, data);
+  dbus_message_unref(msg);
+  return ret;
+}
+
+/**
+ * @brief Eject a Volume
+ *
+ * @param conn the E_DBus_Connection
+ * @param udi the udi of the device object
+ * @param options a list of additional options (not sure... fstype dependent?)
+ * @param cb_func an optional callback to call when the eject is done
+ * @param data cuatom data pointer for the callback function
+ */
+EAPI DBusPendingCall *
+e_hal_device_volume_eject(E_DBus_Connection *conn, const char *udi, Eina_List *options, E_DBus_Callback_Func cb_func, void *data)
+{
+  DBusMessage *msg;
+  DBusMessageIter iter, subiter;
+  Eina_List *l;
+  DBusPendingCall *ret;
+
+  msg = e_hal_device_volume_call_new(udi, "Eject");
+
+  dbus_message_iter_init_append(msg, &iter);
+  if (dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &subiter))
+  {
+    if (options)
+    {
+      const char *opt;
+       
+      EINA_LIST_FOREACH(options, l, opt)
+      {
+        dbus_message_iter_append_basic(&subiter, DBUS_TYPE_STRING, &opt);
+      }
+    }
+    dbus_message_iter_close_container(&iter, &subiter);
+  }
+  else
+  {
+    ERR("dbus_message_iter_open_container() failed");
+  }
+
+  ret = e_dbus_method_call_send(conn, msg, NULL, cb_func, NULL, -1, data);
+  dbus_message_unref(msg);
+  return ret;
+}
diff --git a/src/lib/hal/e_hal_device.h b/src/lib/hal/e_hal_device.h
new file mode 100644 (file)
index 0000000..3fc478a
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef E_HAL_DEVICE_H
+#define E_HAL_DEVICE_H
+
+#include "E_Hal.h"
+
+typedef struct E_Hal_Properties E_Hal_Device_Get_All_Properties_Return;
+typedef struct E_Hal_Property E_Hal_Device_Get_Property_Return;
+typedef struct E_Hal_Bool_Return E_Hal_Device_Query_Capability_Return;
+
+int e_hal_device_get_property(E_DBus_Connection *conn, const char *udi, const char *property, E_Hal_Callback_Func cb_func, void *data);
+int e_hal_device_get_all_properties(E_DBus_Connection *conn, const char *udi, E_Hal_Callback_Func cb_func, void *data);
+int e_hal_device_query_capability(E_DBus_Connection *conn, const char *udi, const char *capability, E_Hal_Callback_Func cb_func, void *data);
+
+#endif
diff --git a/src/lib/hal/e_hal_main.c b/src/lib/hal/e_hal_main.c
new file mode 100644 (file)
index 0000000..c9d217b
--- /dev/null
@@ -0,0 +1,53 @@
+#include <E_Hal.h>
+#include "e_hal_private.h"
+
+int _e_dbus_hal_log_dom = -1;
+int _e_dbus_hal_init_count = 0;
+
+EAPI int
+e_hal_init(void)
+{
+   if (++_e_dbus_hal_init_count != 1)
+     return _e_dbus_hal_init_count;
+
+   if (!eina_init())
+     return --_e_dbus_hal_init_count;
+
+   _e_dbus_hal_log_dom = eina_log_domain_register
+     ("e_hal", E_DBUS_COLOR_DEFAULT);
+   if (_e_dbus_hal_log_dom < 0)
+     {
+       EINA_LOG_ERR("Could not register 'e_hal' log domain.");
+       goto shutdown_eina;
+     }
+
+   if (!e_dbus_init()) {
+      ERR("Could not initialize E_DBus.");
+      goto unregister_log_domain;
+   }
+
+   return _e_dbus_hal_init_count;
+
+ unregister_log_domain:
+   eina_log_domain_unregister(_e_dbus_hal_log_dom);
+   _e_dbus_hal_log_dom = -1;
+ shutdown_eina:
+   eina_shutdown();
+
+   return _e_dbus_hal_init_count;
+}
+
+EAPI int
+e_hal_shutdown(void)
+{
+   if (--_e_dbus_hal_init_count != 0)
+     return _e_dbus_hal_init_count;
+
+   e_dbus_shutdown();
+
+   eina_log_domain_unregister(_e_dbus_hal_log_dom);
+   _e_dbus_hal_log_dom = -1;
+   eina_shutdown();
+
+   return _e_dbus_hal_init_count;
+}
diff --git a/src/lib/hal/e_hal_manager.c b/src/lib/hal/e_hal_manager.c
new file mode 100644 (file)
index 0000000..c22fb8b
--- /dev/null
@@ -0,0 +1,146 @@
+#include <stdlib.h>
+
+#include "E_Hal.h"
+#include "e_hal_private.h"
+
+#define e_hal_manager_call_new(member) dbus_message_new_method_call(E_HAL_SENDER, E_HAL_MANAGER_PATH, E_HAL_MANAGER_INTERFACE, member)
+
+/* GetAllDevices */
+
+static void *
+unmarshal_string_list(DBusMessage *msg, DBusError *err)
+{
+  E_Hal_String_List_Return *ret = NULL;
+  DBusMessageIter iter, sub;
+
+  if (!dbus_message_has_signature(msg, "as")) 
+  {
+    dbus_set_error(err, DBUS_ERROR_INVALID_SIGNATURE, "");
+    return NULL;
+  }
+
+  ret = calloc(1, sizeof(E_Hal_String_List_Return));
+  if (!ret) 
+  {
+    dbus_set_error(err, DBUS_ERROR_NO_MEMORY, "");
+    return NULL;
+  }
+
+  ret->strings = NULL;
+
+  dbus_message_iter_init(msg, &iter);
+  dbus_message_iter_recurse(&iter, &sub);
+  while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID)
+  {
+    char *dev = NULL;
+
+    dbus_message_iter_get_basic(&sub, &dev);
+    if (dev)
+      ret->strings = eina_list_append(ret->strings, eina_stringshare_add(dev));
+    dbus_message_iter_next(&sub);
+  }
+
+  return ret;
+}
+
+static void
+free_string_list(void *data)
+{
+  E_Hal_String_List_Return *ret = data;
+  const char *str;
+
+  if (!ret) return;
+  EINA_LIST_FREE(ret->strings, str)
+    eina_stringshare_del(str);
+  free(ret);
+}
+
+EAPI DBusPendingCall *
+e_hal_manager_get_all_devices(E_DBus_Connection *conn, E_DBus_Callback_Func cb_func, void *data)
+{
+  DBusMessage *msg;
+  DBusPendingCall *ret;
+
+  msg = e_hal_manager_call_new("GetAllDevices");
+  ret = e_dbus_method_call_send(conn, msg, unmarshal_string_list, cb_func, free_string_list, -1, data);
+  dbus_message_unref(msg);
+  return ret;
+}
+
+/* Manager.DeviceExists(string udi) */
+
+static void *
+unmarshal_manager_device_exists(DBusMessage *msg, DBusError *err)
+{
+  E_Hal_Manager_Device_Exists_Return *ret = NULL;
+  dbus_bool_t val;
+
+  ret = calloc(1, sizeof(E_Hal_Manager_Device_Exists_Return));
+  if (!ret) 
+  {
+    dbus_set_error(err, DBUS_ERROR_NO_MEMORY, "");
+    return NULL;
+  }
+
+  dbus_message_get_args(msg, err, DBUS_TYPE_BOOLEAN, &val, DBUS_TYPE_INVALID);
+
+  if (dbus_error_is_set(err))
+  {
+    free(ret);
+    return NULL;
+  }
+
+  ret->boolean = val;
+  return ret;
+}
+
+static void
+free_manager_device_exists(void *data)
+{
+  E_Hal_Manager_Device_Exists_Return *ret = data;
+
+  if (!ret) return;
+  free(ret);
+}
+
+EAPI DBusPendingCall *
+e_hal_manager_device_exists(E_DBus_Connection *conn, const char *udi, E_DBus_Callback_Func cb_func, void *data)
+{
+  DBusPendingCall *ret;
+  DBusMessage *msg;
+
+  msg = e_hal_manager_call_new("DeviceExists");
+  dbus_message_append_args(msg, DBUS_TYPE_STRING, &udi, DBUS_TYPE_INVALID);
+  ret = e_dbus_method_call_send(conn, msg, unmarshal_manager_device_exists, cb_func, free_manager_device_exists, -1, data);
+  dbus_message_unref(msg);
+  return ret;
+}
+
+/* Manager.FindDeviceStringMatch */
+EAPI DBusPendingCall *
+e_hal_manager_find_device_string_match(E_DBus_Connection *conn, const char *key, const char *value, E_DBus_Callback_Func cb_func, void *data)
+{
+  DBusMessage *msg;
+  DBusPendingCall *ret;
+
+  msg = e_hal_manager_call_new("FindDeviceStringMatch");
+  dbus_message_append_args(msg, DBUS_TYPE_STRING, &key, DBUS_TYPE_STRING, &value, DBUS_TYPE_INVALID);
+  ret = e_dbus_method_call_send(conn, msg, unmarshal_string_list, cb_func, free_string_list, -1, data);
+  dbus_message_unref(msg);
+  return ret;
+}
+
+/* Manager.FindDeviceByCapability */
+
+EAPI DBusPendingCall *
+e_hal_manager_find_device_by_capability(E_DBus_Connection *conn, const char *capability, E_DBus_Callback_Func cb_func, void *data)
+{
+  DBusMessage *msg;
+  DBusPendingCall *ret;
+
+  msg = e_hal_manager_call_new("FindDeviceByCapability");
+  dbus_message_append_args(msg, DBUS_TYPE_STRING, &capability, DBUS_TYPE_INVALID);
+  ret = e_dbus_method_call_send(conn, msg, unmarshal_string_list, cb_func, free_string_list, -1, data);
+  dbus_message_unref(msg);
+  return ret;
+}
diff --git a/src/lib/hal/e_hal_manager.h b/src/lib/hal/e_hal_manager.h
new file mode 100644 (file)
index 0000000..3714dde
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef E_HAL_MANAGER_H
+#define E_HAL_MANAGER_H
+
+#include "E_Hal.h"
+
+typedef struct E_Hal_String_List_Return E_Hal_Manager_Get_All_Devices_Return;
+typedef struct E_Hal_Bool_Return E_Hal_Manager_Device_Exists_Return;
+typedef struct E_Hal_String_List_Return E_Hal_Manager_Find_Device_String_Match_Return;
+typedef struct E_Hal_String_List_Return E_Hal_Manager_Find_Device_By_Capability_Return;
+
+typedef struct E_Hal_UDI_Return E_Hal_Manager_Device_Added;
+typedef struct E_Hal_UDI_Return E_Hal_Manager_Device_Removed;
+typedef struct E_Hal_Capability E_Hal_Manager_New_Capability;
+
+
+int e_hal_manager_get_all_devices(E_DBus_Connection *conn, E_Hal_Callback_Func cb_func, void *data);
+int e_hal_manager_device_exists(E_DBus_Connection *conn, const char *udi, E_Hal_Callback_Func cb_func, void *data);
+int e_hal_manager_find_device_string_match(E_DBus_Connection *conn, const char *key, const char *value, E_Hal_Callback_Func cb_func, void *data);
+int e_hal_manager_find_device_by_capability(E_DBus_Connection *conn, const char *capability, E_Hal_Callback_Func cb_func, void *data);
+
+#endif
diff --git a/src/lib/hal/e_hal_private.h b/src/lib/hal/e_hal_private.h
new file mode 100644 (file)
index 0000000..1190714
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef E_HAL_PRIVATE_H
+#define E_HAL_PRIVATE_H
+
+#ifndef E_DBUS_COLOR_DEFAULT
+#define E_DBUS_COLOR_DEFAULT EINA_COLOR_CYAN
+#endif
+extern int _e_dbus_hal_log_dom;
+#ifdef ERR
+#undef ERR
+#endif
+#ifdef INF
+#undef INF
+#endif
+#ifdef WARN
+#undef WARN
+#endif
+#ifdef DBG
+#undef DBG
+#endif
+
+#define DBG(...)   EINA_LOG_DOM_DBG(_e_dbus_hal_log_dom, __VA_ARGS__)
+#define INFO(...)    EINA_LOG_DOM_INFO(_e_dbus_hal_log_dom, __VA_ARGS__)
+#define WARN(...) EINA_LOG_DOM_WARN(_e_dbus_hal_log_dom, __VA_ARGS__)
+#define ERR(...)   EINA_LOG_DOM_ERR(_e_dbus_hal_log_dom, __VA_ARGS__)
+
+#endif
diff --git a/src/lib/hal/e_hal_util.c b/src/lib/hal/e_hal_util.c
new file mode 100644 (file)
index 0000000..b66f35b
--- /dev/null
@@ -0,0 +1,120 @@
+#include <stdlib.h>
+
+#include <E_Hal.h>
+#include <string.h>
+#include "e_hal_private.h"
+
+/**
+ * @internal
+ * @brief free a property structure
+ * @param prop the property to free
+ */
+EAPI void
+e_hal_property_free(E_Hal_Property *prop)
+{
+  if (prop->type == E_HAL_PROPERTY_TYPE_STRLIST)
+  {
+    const char *str;
+    EINA_LIST_FREE(prop->val.strlist, str)
+      eina_stringshare_del(str);
+  }
+  else if (prop->type == E_HAL_PROPERTY_TYPE_STRING)
+    eina_stringshare_del(prop->val.s);
+  free(prop);
+}
+
+/**
+ * @brief Retrive a string from an element of a property hash
+ * @param properties the E_Hal_Properties structure
+ * @param key the key of the property to retrieve
+ * @param err a pointer to an int, which if supplied, will be set to 0 on success and 1 on an error
+ */
+EAPI const char *
+e_hal_property_string_get(E_Hal_Properties *properties, const char *key, int *err)
+{
+  E_Hal_Property *prop;
+  if (err) *err = 0;
+  if (!properties) return NULL;
+  if (!properties->properties) return NULL;
+  if (!key) return NULL;
+  prop = eina_hash_find(properties->properties, key);
+  if (prop) return prop->val.s;
+
+  if (err) *err = 1;
+  return NULL;
+}
+
+EAPI Eina_Bool
+e_hal_property_bool_get(E_Hal_Properties *properties, const char *key, int *err)
+{
+  E_Hal_Property *prop;
+  if (err) *err = 0;
+  if (!properties) return EINA_FALSE;
+  if (!properties->properties) return EINA_FALSE;
+  if (!key) return EINA_FALSE;
+  prop = eina_hash_find(properties->properties, key);
+  if (prop) return prop->val.b;
+  
+  if (err) *err = 1;
+  return EINA_FALSE;
+}
+
+EAPI int
+e_hal_property_int_get(E_Hal_Properties *properties, const char *key, int *err)
+{
+  E_Hal_Property *prop;
+  if (err) *err = 0;
+  if (!properties) return 0;
+  if (!properties->properties) return 0;
+  if (!key) return 0;
+  prop = eina_hash_find(properties->properties, key);
+  if (prop) return prop->val.i;
+
+  if (err) *err = 1;
+  return 0;
+}
+
+EAPI uint64_t
+e_hal_property_uint64_get(E_Hal_Properties *properties, const char *key, int *err)
+{
+  E_Hal_Property *prop;
+  if (err) *err = 0;
+  if (!properties) return 0;
+  if (!properties->properties) return 0;
+  if (!key) return 0;
+  prop = eina_hash_find(properties->properties, key);
+  if (prop) return prop->val.u64;
+
+  if (err) *err = 1;
+  return 0;
+}
+
+EAPI double
+e_hal_property_double_get(E_Hal_Properties *properties, const char *key, int *err)
+{
+  E_Hal_Property *prop;
+  if (err) *err = 0;
+  if (!properties) return 0;
+  if (!properties->properties) return 0;
+  if (!key) return 0;
+  prop = eina_hash_find(properties->properties, key);
+  if (prop) return prop->val.d;
+
+  if (err) *err = 1;
+  return 0;
+}
+
+EAPI const Eina_List *
+e_hal_property_strlist_get(E_Hal_Properties *properties, const char *key, int *err)
+{
+  E_Hal_Property *prop;
+  if (err) *err = 0;
+  if (!properties) return NULL;
+  if (!properties->properties) return NULL;
+  if (!key) return NULL;
+  prop = eina_hash_find(properties->properties, key);
+  if (prop) return prop->val.strlist;
+
+  if (err) *err = 1;
+  return NULL;
+}
diff --git a/src/lib/hal/e_hal_util.h b/src/lib/hal/e_hal_util.h
new file mode 100644 (file)
index 0000000..0413510
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef E_HAL_UTIL_H
+#define E_HAL_UTIL_H
+
+#include "E_Hal.h"
+
+void e_hal_property_free(E_Hal_Property *prop);
+const char *e_hal_property_string_get(E_Hal_Properties *properties, const char *key, int *err);
+char e_hal_property_bool_get(E_Hal_Properties *properties, const char *key, int *err);
+int e_hal_property_int_get(E_Hal_Properties *properties, const char *key, int *err);
+uint64_t e_hal_property_uint64_get(E_Hal_Properties *properties, const char *key, int *err);
+double e_hal_property_double_get(E_Hal_Properties *properties, const char *key, int *err);
+const Eina_List *e_hal_property_strlist_get(E_Hal_Properties *properties, const char *key, int *err);
+
+#endif
diff --git a/src/lib/notification/E_Notification_Daemon.h b/src/lib/notification/E_Notification_Daemon.h
new file mode 100644 (file)
index 0000000..fc530ba
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef E_NOTIFICATION_DAEMON_H
+#define E_NOTIFICATION_DAEMON_H
+
+#define E_NOTIFICATION_DAEMON_VERSION "0.9"
+#define E_NOTIFICATION_DAEMON_SUPPORTS_SPEC_VERSION "1.2"
+#include <E_Notify.h>
+
+#ifdef EAPI
+#undef EAPI
+#endif
+#ifdef _MSC_VER
+# ifdef BUILDING_DLL
+#  define EAPI __declspec(dllexport)
+# else
+#  define EAPI __declspec(dllimport)
+# endif
+#else
+# ifdef __GNUC__
+#  if __GNUC__ >= 4
+#   define EAPI __attribute__ ((visibility("default")))
+#  else
+#   define EAPI
+#  endif
+# else
+#  define EAPI
+# endif
+#endif
+
+
+typedef struct E_Notification_Daemon E_Notification_Daemon;
+
+/* daemon callbacks */
+typedef int (*E_Notification_Daemon_Callback_Notify) (E_Notification_Daemon *daemon, E_Notification *notification);
+typedef void (*E_Notification_Daemon_Callback_Close_Notification) (E_Notification_Daemon *daemon, unsigned int notification_id);
+
+/* gui */
+typedef struct E_Notification_View E_Notification_View;
+
+struct E_Notification_Daemon
+{
+  E_DBus_Connection *conn;
+  E_DBus_Interface *iface;
+  E_DBus_Object *obj;
+
+  char *name;
+  char *vendor;
+
+  struct 
+  {
+    E_Notification_Daemon_Callback_Notify notify;
+    E_Notification_Daemon_Callback_Close_Notification close_notification;
+  } func;
+  void *data;
+
+  int state;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  EAPI int e_notification_daemon_init(void);
+  EAPI int e_notification_daemon_shutdown(void);
+
+/* daemon */
+   EAPI E_Notification_Daemon *e_notification_daemon_add(const char *name, const char *vendor);
+   EAPI void e_notification_daemon_free(E_Notification_Daemon *d);
+/* TODO
+   void e_notification_daemon_close(E_Notification_Daemon *d,
+   E_Notification *n, unsigned int reason);
+   void e_notification_daemon_action_invoke(E_Notification_Daemon *d,
+   E_Notification *n, const char *action_id);
+*/
+
+   EAPI void  e_notification_daemon_data_set(E_Notification_Daemon *daemon, void *data);
+   EAPI void *e_notification_daemon_data_get(E_Notification_Daemon *daemon);
+
+   EAPI void e_notification_daemon_callback_notify_set(E_Notification_Daemon *daemon, E_Notification_Daemon_Callback_Notify func);
+   EAPI void e_notification_daemon_callback_close_notification_set(E_Notification_Daemon *daemon, E_Notification_Daemon_Callback_Close_Notification func);
+
+   EAPI void e_notification_daemon_signal_notification_closed(E_Notification_Daemon *daemon, unsigned int id, E_Notification_Closed_Reason reason);
+   EAPI void e_notification_daemon_signal_action_invoked(E_Notification_Daemon *daemon, unsigned int notification_id, const char *action_id);
+
+/***** gui *****/
+/* TODO
+   E_Notification_View *e_notification_view_add(E_Notification_Daemon *d, E_Notification *n);
+   void e_notification_view_close(E_Notification_View *nv);
+   Evas_Object * e_notification_view_icon_get(Evas *evas, E_Notification *n);
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/notification/E_Notify.h b/src/lib/notification/E_Notify.h
new file mode 100644 (file)
index 0000000..7fdf5c6
--- /dev/null
@@ -0,0 +1,190 @@
+#ifndef E_NOTIFY_H
+#define E_NOTIFY_H
+
+#include <Eina.h>
+#include <Evas.h>
+#include <E_DBus.h>
+
+/**
+ * @defgroup ENotify_Group ENotify
+ *
+ * @{
+ */
+
+
+/* notifications */
+typedef struct E_Notification_Image E_Notification_Image;
+typedef struct E_Notification E_Notification;
+typedef struct E_Notification_Action E_Notification_Action;
+
+typedef enum E_Notification_Urgency E_Notification_Urgency;
+typedef enum E_Notification_Hint_Type E_Notification_Hint_Type;
+typedef enum E_Notification_Closed_Reason E_Notification_Closed_Reason;
+
+/* method returns */
+typedef struct E_Notification_Return_Notify E_Notification_Return_Notify;
+typedef struct E_Notification_Return_Get_Capabilities E_Notification_Return_Get_Capabilities;
+typedef struct E_Notification_Return_Get_Server_Information E_Notification_Return_Get_Server_Information;
+
+
+/* signal events */
+typedef struct E_Notification_Event_Action_Invoked E_Notification_Event_Action_Invoked;
+typedef struct E_Notification_Event_Notification_Closed E_Notification_Event_Notification_Closed;
+
+/* enums */
+
+enum E_Notification_Urgency
+{
+  E_NOTIFICATION_URGENCY_LOW,
+  E_NOTIFICATION_URGENCY_NORMAL,
+  E_NOTIFICATION_URGENCY_CRITICAL
+};
+
+enum E_Notification_Closed_Reason
+{
+  E_NOTIFICATION_CLOSED_EXPIRED,
+  E_NOTIFICATION_CLOSED_DISMISSED,
+  E_NOTIFICATION_CLOSED_REQUESTED,
+  E_NOTIFICATION_CLOSED_UNDEFINED
+};
+
+enum E_Notification_Hint_Type
+{
+  E_NOTIFICATION_HINT_URGENCY        = (1 << 0),
+  E_NOTIFICATION_HINT_CATEGORY       = (1 << 1),
+  E_NOTIFICATION_HINT_DESKTOP        = (1 << 2),
+  E_NOTIFICATION_HINT_SOUND_FILE     = (1 << 3),
+  E_NOTIFICATION_HINT_TRANSIENT      = (1 << 4),
+  E_NOTIFICATION_HINT_RESIDENT       = (1 << 5),
+  E_NOTIFICATION_HINT_ACTION_ICONS   = (1 << 6),
+  E_NOTIFICATION_HINT_SUPPRESS_SOUND = 0x10,
+  E_NOTIFICATION_HINT_XY             = 0x20,
+  E_NOTIFICATION_HINT_IMAGE_DATA     = 0x40
+};
+
+/* client method returns */
+struct E_Notification_Return_Notify
+{
+  unsigned int notification_id;
+  E_Notification *notification;
+};
+
+struct E_Notification_Return_Get_Capabilities
+{
+  Eina_List *capabilities;
+};
+
+struct E_Notification_Return_Get_Server_Information
+{
+  const char *name;
+  const char *vendor;
+  const char *version;
+  const char *spec_version;
+};
+
+/* signals */
+struct E_Notification_Event_Notification_Closed
+{
+  unsigned int notification_id;
+  E_Notification_Closed_Reason reason;
+};
+
+struct E_Notification_Event_Action_Invoked
+{
+  unsigned int notification_id;
+  char *action_id;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+   EAPI int e_notification_init(void);
+   EAPI int e_notification_shutdown(void);
+
+/* client */
+   EAPI void e_notification_send(E_Notification *n, E_DBus_Callback_Func func, void *data);
+   EAPI void e_notification_get_capabilities(E_DBus_Callback_Func func, void *data);
+   EAPI void e_notification_get_server_information(E_DBus_Callback_Func func, void *data);
+
+
+/* Notifications */
+
+   EAPI E_Notification *e_notification_new(void);
+   EAPI void e_notification_ref(E_Notification *n);
+   EAPI void e_notification_unref(E_Notification *n);
+   EAPI void e_notification_free(E_Notification *n);
+
+   EAPI E_Notification *e_notification_full_new(const char *app_name,
+                                                unsigned int replaces_id,
+                                                const char *app_icon,
+                                                const char *summary,
+                                                const char *body,
+                                                int expire_timeout);
+
+/* notification mutators */
+   EAPI void e_notification_id_set(E_Notification *note, unsigned int id);
+   EAPI void e_notification_app_name_set(E_Notification *n, const char *app_name);
+   EAPI void e_notification_app_icon_set(E_Notification *n, const char *app_icon);
+   EAPI void e_notification_summary_set(E_Notification *n, const char *summary);
+   EAPI void e_notification_body_set(E_Notification *n, const char *body);
+   EAPI void e_notification_replaces_id_set(E_Notification *n, int replaces_id);
+   EAPI void e_notification_timeout_set(E_Notification *n, int timeout);
+   EAPI void e_notification_closed_set(E_Notification *note, unsigned char closed);
+
+/* notification accessors */
+   EAPI unsigned int e_notification_id_get(E_Notification *note);
+   EAPI const char *e_notification_app_name_get(E_Notification *n);
+   EAPI const char *e_notification_app_icon_get(E_Notification *n);
+   EAPI const char *e_notification_summary_get(E_Notification *n);
+   EAPI const char *e_notification_body_get(E_Notification *n);
+   EAPI int e_notification_replaces_id_get(E_Notification *note);
+   EAPI int e_notification_timeout_get(E_Notification *note);
+   EAPI unsigned char e_notification_closed_get(E_Notification *note);
+
+/* actions */
+   EAPI void e_notification_action_add(E_Notification *n, const char *action_id, const char *action_name);
+   EAPI Eina_List *e_notification_actions_get(E_Notification *n);
+   EAPI const char *e_notification_action_id_get(E_Notification_Action *a);
+   EAPI const char *e_notification_action_name_get(E_Notification_Action *a);
+
+/* hint mutators */
+   EAPI void e_notification_hint_transient_set(E_Notification *n, Eina_Bool transient);
+   EAPI void e_notification_hint_resident_set(E_Notification *n, Eina_Bool resident);
+   EAPI void e_notification_hint_action_icons_set(E_Notification *n, Eina_Bool action_icons);
+   EAPI void e_notification_hint_image_path_set(E_Notification *n, const char *path);
+   EAPI void e_notification_hint_urgency_set(E_Notification *n, char urgency);
+   EAPI void e_notification_hint_category_set(E_Notification *n, const char *category);
+   EAPI void e_notification_hint_desktop_set(E_Notification *n, const char *desktop);
+   EAPI void e_notification_hint_sound_file_set(E_Notification *n, const char *sound_file);
+   EAPI void e_notification_hint_suppress_sound_set(E_Notification *n, char suppress_sound);
+   EAPI void e_notification_hint_xy_set(E_Notification *n, int x, int y);
+   EAPI void e_notification_hint_image_data_set(E_Notification *n, E_Notification_Image *image);
+
+/* hint accessors */
+   EAPI char  e_notification_hint_urgency_get(E_Notification *n);
+   EAPI const char *e_notification_hint_category_get(E_Notification *n);
+   EAPI const char *e_notification_hint_desktop_get(E_Notification *n);
+   EAPI const char *e_notification_hint_sound_file_get(E_Notification *n);
+   EAPI const char *e_notification_hint_image_path_get(E_Notification *n);
+   EAPI char  e_notification_hint_suppress_sound_get(E_Notification *n);
+   EAPI int   e_notification_hint_xy_get(E_Notification *n, int *x, int *y);
+   EAPI E_Notification_Image *e_notification_hint_image_data_get(E_Notification *n);
+   /* icon_data is deprecated, we do not support setting it */
+   EAPI E_Notification_Image *e_notification_hint_icon_data_get(E_Notification *n);
+
+/* image hint */
+   EAPI E_Notification_Image *e_notification_image_new(void);
+   EAPI void e_notification_image_free(E_Notification_Image *img);
+   EAPI Eina_Bool e_notification_image_init(E_Notification_Image *img, Evas_Object *obj) EINA_WARN_UNUSED_RESULT;
+   EAPI Evas_Object *e_notification_image_evas_object_add(Evas *evas, E_Notification_Image *img);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/src/lib/notification/Makefile.am b/src/lib/notification/Makefile.am
new file mode 100644 (file)
index 0000000..d2cc308
--- /dev/null
@@ -0,0 +1,24 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I $(top_srcdir)/src/lib/dbus \
+@EDBUS_CFLAGS@ \
+@EVAS_CFLAGS@
+
+lib_LTLIBRARIES = libenotify.la
+includes_HEADERS = E_Notify.h E_Notification_Daemon.h
+includesdir = $(includedir)/e_dbus-@VMAJ@
+
+libenotify_la_SOURCES = \
+notification.c \
+marshal.c \
+client.c \
+daemon.c
+
+libenotify_la_LIBADD = \
+@EDBUS_LIBS@ $(top_builddir)/src/lib/dbus/libedbus.la \
+@EVAS_LIBS@
+
+libenotify_la_LDFLAGS = -version-info @version_info@ @release_info@
+
+EXTRA_DIST = e_notify_private.h
diff --git a/src/lib/notification/client.c b/src/lib/notification/client.c
new file mode 100644 (file)
index 0000000..30ca889
--- /dev/null
@@ -0,0 +1,63 @@
+#include "E_Notify.h"
+#include "e_notify_private.h"
+
+static E_DBus_Connection *client_conn;
+static int init_count = 0;
+
+EAPI int
+e_notification_init(void)
+{
+   if (init_count) return ++init_count;
+
+   if (!e_dbus_init()) return 0;
+   client_conn = e_dbus_bus_get(DBUS_BUS_SESSION);
+   if (!client_conn)
+     {
+        e_dbus_shutdown();
+        return 0;
+     }
+
+   return ++init_count;
+}
+
+EAPI int
+e_notification_shutdown(void)
+{
+   if (--init_count) return init_count;
+   e_dbus_connection_close(client_conn);
+   client_conn = NULL;
+   e_dbus_shutdown();
+   return 0;
+}
+
+/**** client api ****/
+EAPI void
+e_notification_send(E_Notification *n, E_DBus_Callback_Func func, void *data)
+{
+   DBusMessage *msg;
+
+   msg = e_notify_marshal_notify(n);
+   e_dbus_method_call_send(client_conn, msg, e_notify_unmarshal_notify_return, func, e_notify_free_notify_return, -1, data);
+   dbus_message_unref(msg);
+}
+
+EAPI void
+e_notification_get_capabilities(E_DBus_Callback_Func func, void *data)
+{
+   DBusMessage *msg;
+
+   msg = e_notify_marshal_get_capabilities();
+   e_dbus_method_call_send(client_conn, msg, e_notify_unmarshal_get_capabilities_return, func, e_notify_free_get_capabilities_return, -1, data);
+   dbus_message_unref(msg);
+}
+
+EAPI void
+e_notification_get_server_information(E_DBus_Callback_Func func, void *data)
+{
+   DBusMessage *msg;
+
+   msg = e_notify_marshal_get_server_information();
+   e_dbus_method_call_send(client_conn, msg, e_notify_unmarshal_get_server_information_return, func, e_notify_free_get_server_information_return, -1, data);
+   dbus_message_unref(msg);
+}
+
diff --git a/src/lib/notification/daemon.c b/src/lib/notification/daemon.c
new file mode 100644 (file)
index 0000000..be01e5e
--- /dev/null
@@ -0,0 +1,246 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "E_Notify.h"
+#include "E_Notification_Daemon.h"
+#include "e_notify_private.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+static int init_count = 0;
+static E_DBus_Interface *daemon_iface = NULL;
+
+static int e_notification_daemon_bus_init(E_Notification_Daemon *ndaemon);
+static int e_notification_daemon_object_init(E_Notification_Daemon *ndaemon);
+
+DBusMessage *
+method_get_capabilities(E_DBus_Object *obj __UNUSED__, DBusMessage *message)
+{
+   const char *capabilities[] = {
+      "body",
+      "actions",
+      NULL
+   };
+   return e_notify_marshal_get_capabilities_return(message, capabilities);
+}
+
+DBusMessage *
+method_notify(E_DBus_Object *obj, DBusMessage *message)
+{
+   E_Notification *n;
+   E_Notification_Daemon *ndaemon;
+   int id = -1;
+
+   ndaemon = e_dbus_object_data_get(obj);
+   n = e_notify_unmarshal_notify(message, NULL);
+   if (ndaemon->func.notify)
+     id = ndaemon->func.notify(ndaemon, n);
+   else
+     return dbus_message_new_error(message, E_NOTIFICATION_INTERFACE ".Unimplemented", "This functionality has not yet been implemented");
+
+   e_notification_unref(n);
+   return e_notify_marshal_notify_return(message, id);
+}
+
+DBusMessage *
+method_close_notification(E_DBus_Object *obj, DBusMessage *message)
+{
+   E_Notification_Daemon *ndaemon;
+   dbus_uint32_t id;
+
+   ndaemon = e_dbus_object_data_get(obj);
+   id = e_notify_unmarshal_close_notification(message, NULL);
+   if (ndaemon->func.close_notification)
+     ndaemon->func.close_notification(ndaemon, id);
+   return dbus_message_new_method_return(message);
+}
+
+DBusMessage *
+method_get_server_information(E_DBus_Object *obj, DBusMessage *message)
+{
+   E_Notification_Daemon *ndaemon;
+
+   ndaemon = e_dbus_object_data_get(obj);
+
+   return e_notify_marshal_get_server_information_return(message, ndaemon->name, ndaemon->vendor, E_NOTIFICATION_DAEMON_VERSION, E_NOTIFICATION_DAEMON_SUPPORTS_SPEC_VERSION);
+}
+
+/**** daemon api ****/
+
+EAPI int
+e_notification_daemon_init(void)
+{
+   if (init_count) return ++init_count;
+   if (!e_dbus_init()) return 0;
+
+   daemon_iface = e_dbus_interface_new(E_NOTIFICATION_INTERFACE);
+
+   return ++init_count;
+}
+
+EAPI int
+e_notification_daemon_shutdown(void)
+{
+   if (--init_count) return init_count;
+   e_dbus_shutdown();
+   return 0;
+}
+
+EAPI E_Notification_Daemon *
+e_notification_daemon_add(const char *name, const char *vendor)
+{
+   E_Notification_Daemon *ndaemon;
+
+   loginit();
+   ndaemon = calloc(1, sizeof(E_Notification_Daemon));
+   if (ndaemon)
+     e_notification_daemon_bus_init(ndaemon);
+
+   if (!ndaemon || !ndaemon->conn)
+     {
+        if (ndaemon) free(ndaemon);
+        e_dbus_shutdown();
+        return NULL;
+     }
+
+   ndaemon->name = strdup(name);
+   ndaemon->vendor = strdup(vendor);
+
+   e_dbus_interface_ref(daemon_iface);
+   ndaemon->iface = daemon_iface;
+   e_dbus_interface_method_add(ndaemon->iface, "GetCapabilities", "", "as", method_get_capabilities);
+   e_dbus_interface_method_add(ndaemon->iface, "Notify", "susssasa{sv}i", "u", method_notify);
+   e_dbus_interface_method_add(ndaemon->iface, "CloseNotification", "u", "u", method_close_notification);
+   e_dbus_interface_method_add(ndaemon->iface, "GetServerInformation", "", "ssss", method_get_server_information);
+
+   return ndaemon;
+}
+
+EAPI void
+e_notification_daemon_free(E_Notification_Daemon *ndaemon)
+{
+   e_dbus_release_name(ndaemon->conn, E_NOTIFICATION_BUS_NAME, NULL, NULL);
+   if (ndaemon->obj)
+     {
+        e_dbus_object_interface_detach(ndaemon->obj, ndaemon->iface);
+        e_dbus_object_free(ndaemon->obj);
+     }
+   if (ndaemon->conn) e_dbus_connection_close(ndaemon->conn);
+   if (ndaemon->name) free(ndaemon->name);
+   if (ndaemon->vendor) free(ndaemon->vendor);
+   if (ndaemon->iface) e_dbus_interface_unref(ndaemon->iface);
+   free(ndaemon);
+}
+
+EAPI void
+e_notification_daemon_data_set(E_Notification_Daemon *ndaemon, void *data)
+{
+   ndaemon->data = data;
+}
+
+EAPI void *
+e_notification_daemon_data_get(E_Notification_Daemon *ndaemon)
+{
+   return ndaemon->data;
+}
+
+EAPI void
+e_notification_daemon_callback_notify_set(E_Notification_Daemon *ndaemon, E_Notification_Daemon_Callback_Notify func)
+{
+   ndaemon->func.notify = func;
+}
+
+EAPI void
+e_notification_daemon_callback_close_notification_set(E_Notification_Daemon *ndaemon, E_Notification_Daemon_Callback_Close_Notification func)
+{
+   ndaemon->func.close_notification = func;
+}
+
+static void
+cb_request_name(void *data, DBusMessage *msg, DBusError *err)
+{
+   E_Notification_Daemon *ndaemon = data;
+   dbus_uint32_t ret;
+   DBusError new_err;
+
+   if (dbus_error_is_set(err))
+     {
+        ERR("request_name: %s", err->message);
+        dbus_error_free(err);
+        return;
+     }
+
+   INF("received response with signature: '%s'",
+       dbus_message_get_signature(msg));
+   dbus_error_init(&new_err);
+   dbus_message_get_args
+     (msg, &new_err, DBUS_TYPE_UINT32, &ret, DBUS_TYPE_INVALID);
+   if (dbus_error_is_set(&new_err))
+     {
+        ERR("req name unmarshal: %s", new_err.message);
+        dbus_error_free(&new_err);
+        return;
+     }
+
+   switch (ret)
+     {
+      case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
+      case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
+        e_notification_daemon_object_init(ndaemon);
+        break;
+
+      case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
+        //XXX mark ndaemon as queued?
+        break;
+
+      case DBUS_REQUEST_NAME_REPLY_EXISTS:
+        //XXX exit?
+        break;
+     }
+}
+
+static int
+e_notification_daemon_bus_init(E_Notification_Daemon *ndaemon)
+{
+   ndaemon->conn = e_dbus_bus_get(DBUS_BUS_SESSION);
+   if (!ndaemon->conn) return 0;
+
+   // this blocks... make it async, and handle failure, etc
+   e_dbus_request_name(ndaemon->conn, E_NOTIFICATION_BUS_NAME, DBUS_NAME_FLAG_REPLACE_EXISTING, cb_request_name, ndaemon);
+
+   return 1;
+}
+
+static int
+e_notification_daemon_object_init(E_Notification_Daemon *ndaemon)
+{
+   if (!ndaemon || !ndaemon->conn) return 0;
+   ndaemon->obj = e_dbus_object_add(ndaemon->conn, E_NOTIFICATION_PATH, ndaemon);
+   if (!ndaemon->obj) return 0;
+
+   e_dbus_object_interface_attach(ndaemon->obj, ndaemon->iface);
+
+   return 1;
+}
+
+EAPI void
+e_notification_daemon_signal_notification_closed(E_Notification_Daemon *ndaemon, unsigned int id, E_Notification_Closed_Reason reason)
+{
+   DBusMessage *msg = e_notify_marshal_notification_closed_signal(id, reason);
+   e_dbus_message_send(ndaemon->conn,
+                       msg,
+                       NULL, -1, NULL);
+   dbus_message_unref(msg);
+}
+
+EAPI void
+e_notification_daemon_signal_action_invoked(E_Notification_Daemon *ndaemon, unsigned int notification_id, const char *action_id)
+{
+   DBusMessage *msg = e_notify_marshal_action_invoked_signal(notification_id, action_id);
+   e_dbus_message_send(ndaemon->conn,
+                       msg,
+                       NULL, -1, NULL);
+   dbus_message_unref(msg);
+}
diff --git a/src/lib/notification/e_notify_private.h b/src/lib/notification/e_notify_private.h
new file mode 100644 (file)
index 0000000..8a29e7c
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef E_NOTIFY_PRIVATE_H
+#define E_NOTIFY_PRIVATE_H
+
+#define E_NOTIFICATION_BUS_NAME "org.freedesktop.Notifications"
+#define E_NOTIFICATION_INTERFACE "org.freedesktop.Notifications"
+#define E_NOTIFICATION_PATH "/org/freedesktop/Notifications"
+
+#define e_notification_call_new(member) dbus_message_new_method_call(E_NOTIFICATION_BUS_NAME, E_NOTIFICATION_PATH, E_NOTIFICATION_INTERFACE, member)
+
+typedef void (*E_DBus_Variant_Marshaller) (DBusMessageIter *iter, void *data);
+#define E_DBUS_VARIANT_MARSHALLER(x) ((E_DBus_Variant_Marshaller)(x))
+
+void e_notify_marshal_dict_variant(DBusMessageIter *iter, const char *key, char *type_str, E_DBus_Variant_Marshaller func, void *data);
+void e_notify_marshal_dict_string(DBusMessageIter *iter, const char *key, const char *value);
+void e_notify_marshal_dict_byte(DBusMessageIter *iter, const char *key, char value);
+void e_notify_marshal_dict_int(DBusMessageIter *iter, const char *key, int value);
+
+void e_notify_marshal_string_array(DBusMessageIter *iter, const char **strings);
+void e_notify_marshal_string_list_as_array(DBusMessageIter *iter, Eina_List *strings);
+Eina_List * e_notify_unmarshal_string_array_as_list(DBusMessageIter *iter, DBusError *err);
+DBusMessage * e_notify_marshal_get_capabilities();
+DBusMessage * e_notify_marshal_get_capabilities_return(DBusMessage *method_call, const char **capabilities);
+void * e_notify_unmarshal_get_capabilities_return(DBusMessage *msg, DBusError *err);
+void   e_notify_free_get_capabilities_return(void *data);
+DBusMessage * e_notify_marshal_get_server_information();
+DBusMessage * e_notify_marshal_get_server_information_return(DBusMessage *method_call, const char *name, const char *vendor, const char *version, const char *spec_version);
+void * e_notify_unmarshal_get_server_information_return(DBusMessage *msg, DBusError *err);
+void   e_notify_free_get_server_information_return(void *data);
+DBusMessage * e_notify_marshal_close_notification(dbus_uint32_t id);
+dbus_uint32_t e_notify_unmarshal_close_notification(DBusMessage *msg, DBusError *err);
+DBusMessage * e_notify_marshal_notification_closed_signal(dbus_uint32_t id, dbus_uint32_t reason);
+E_Notification_Event_Notification_Closed * e_notify_unmarshal_notification_closed_signal(DBusMessage *msg, DBusError *err);
+DBusMessage * e_notify_marshal_action_invoked_signal(dbus_uint32_t id, const char *action_id);
+E_Notification_Event_Action_Invoked * e_notify_unmarshal_action_invoked_signal(DBusMessage *msg, DBusError *err);
+DBusMessage * e_notify_marshal_notify(E_Notification *n);
+E_Notification * e_notify_unmarshal_notify(DBusMessage *msg, DBusError *err);
+DBusMessage * e_notify_marshal_notify_return(DBusMessage *method_call, dbus_uint32_t notification_id);
+void * e_notify_unmarshal_notify_return(DBusMessage *msg, DBusError *err);
+void   e_notify_free_notify_return(void *data);
+void e_notify_unmarshal_notify_actions(E_Notification *n, DBusMessageIter *iter);
+void e_notify_unmarshal_notify_hints(E_Notification *n, DBusMessageIter *iter);
+void e_notify_marshal_hint_image(DBusMessageIter *iter, E_Notification_Image *img);
+E_Notification_Image * e_notify_unmarshal_hint_image(DBusMessageIter *iter);
+void loginit(void);
+extern int _e_dbus_notify_log_dom;
+
+#ifndef E_DBUS_COLOR_DEFAULT
+#define E_DBUS_COLOR_DEFAULT EINA_COLOR_CYAN
+#endif
+
+#undef DBG
+#undef INF
+#undef WRN
+#undef ERR
+
+#define DBG(...) EINA_LOG_DOM_DBG(_e_dbus_notify_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_e_dbus_notify_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_e_dbus_notify_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_e_dbus_notify_log_dom, __VA_ARGS__)
+
+struct E_Notification_Image
+{
+  int   width;
+  int   height;
+  int   rowstride;
+  char  has_alpha;
+  int   bits_per_sample;
+  int   channels;
+  unsigned char *data;
+};
+
+struct E_Notification
+{
+  int id;
+  const char *app_name;
+  unsigned int replaces_id;
+  const char *app_icon;
+  const char *summary;
+  const char *body;
+  int expire_timeout;
+
+  Eina_List *actions;
+
+  struct
+  {
+    char urgency;
+    const char *category;
+    const char *desktop;
+    const char *sound_file;
+    const char *image_path;
+    char suppress_sound;
+    int x, y;
+    E_Notification_Image *image_data;
+    E_Notification_Image *icon_data;
+  } hints;
+
+  int hint_flags;
+  unsigned char closed;
+
+  int refcount;
+};
+
+struct E_Notification_Action 
+{
+  const char *id;
+  const char *name;
+};
+
+#endif
diff --git a/src/lib/notification/marshal.c b/src/lib/notification/marshal.c
new file mode 100644 (file)
index 0000000..ec4fbbd
--- /dev/null
@@ -0,0 +1,706 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "E_Notify.h"
+#include "e_notify_private.h"
+
+void
+e_notify_marshal_dict_variant(DBusMessageIter *iter, const char *key, char *type_str, E_DBus_Variant_Marshaller func, void *data)
+{
+   DBusMessageIter entry, variant;
+
+   if (dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry))
+     {
+        dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+        if (dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, type_str, &variant))
+          {
+             func(&variant, data);
+             dbus_message_iter_close_container(&entry, &variant);
+          }
+        else
+          {
+             ERR("dbus_message_iter_open_container() failed");
+          }
+        dbus_message_iter_close_container(iter, &entry);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+}
+
+void
+e_notify_marshal_dict_string(DBusMessageIter *iter, const char *key, const char *value)
+{
+   DBusMessageIter entry, variant;
+
+   if (dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry))
+     {
+        dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+        if (dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "s", &variant))
+          {
+             dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &value);
+             dbus_message_iter_close_container(&entry, &variant);
+          }
+        else
+          {
+             ERR("dbus_message_iter_open_container() failed");
+          }
+        dbus_message_iter_close_container(iter, &entry);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+}
+
+void
+e_notify_marshal_dict_byte(DBusMessageIter *iter, const char *key, char value)
+{
+   DBusMessageIter entry, variant;
+
+   if (!key || !value) return;
+
+   if (dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry))
+     {
+        dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+        if (dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "y", &variant))
+          {
+             dbus_message_iter_append_basic(&variant, DBUS_TYPE_BYTE, &value);
+             dbus_message_iter_close_container(&entry, &variant);
+          }
+        else
+          {
+             ERR("dbus_message_iter_open_container() failed");
+          }
+        dbus_message_iter_close_container(iter, &entry);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+}
+
+void
+e_notify_marshal_dict_int(DBusMessageIter *iter, const char *key, int value)
+{
+   DBusMessageIter entry, variant;
+
+   if (!key || !value) return;
+
+   if (dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry))
+     {
+        dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+        if (dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "i", &variant))
+          {
+             dbus_message_iter_append_basic(&variant, DBUS_TYPE_INT32, &value);
+             dbus_message_iter_close_container(&entry, &variant);
+          }
+        else
+          {
+             ERR("dbus_message_iter_open_container() failed");
+          }
+        dbus_message_iter_close_container(iter, &entry);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+}
+
+void
+e_notify_marshal_string_array(DBusMessageIter *iter, const char **strings)
+{
+   const char **str;
+   DBusMessageIter arr;
+
+   if (dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &arr))
+     {
+        for (str = strings; *str; str++)
+          dbus_message_iter_append_basic(&arr, DBUS_TYPE_STRING, str);
+        dbus_message_iter_close_container(iter, &arr);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+}
+
+void
+e_notify_marshal_string_list_as_array(DBusMessageIter *iter, Eina_List *strings)
+{
+   const char *str;
+   DBusMessageIter arr;
+   Eina_List *l;
+
+   if (dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &arr))
+     {
+        EINA_LIST_FOREACH (strings, l, str)
+          dbus_message_iter_append_basic(&arr, DBUS_TYPE_STRING, &str);
+        dbus_message_iter_close_container(iter, &arr);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+}
+
+Eina_List *
+e_notify_unmarshal_string_array_as_list(DBusMessageIter *iter, DBusError *err __UNUSED__)
+{
+   Eina_List *strings;
+   char *sig;
+   int ret;
+   DBusMessageIter arr;
+
+   sig = dbus_message_iter_get_signature(iter);
+   ret = !strcmp(sig, "as");
+   dbus_free(sig);
+   if (!ret) return NULL;
+
+   strings = NULL;
+
+   dbus_message_iter_recurse(iter, &arr);
+   while (dbus_message_iter_has_next(&arr))
+     {
+        const char *str;
+        dbus_message_iter_get_basic(&arr, &str);
+        strings = eina_list_append(strings, eina_stringshare_add(str)); //XXX use eina_stringshare_instance?
+        dbus_message_iter_next(&arr);
+     }
+   return strings;
+}
+
+DBusMessage *
+e_notify_marshal_get_capabilities()
+{
+   DBusMessage *msg;
+
+   msg = e_notification_call_new("GetCapabilities");
+   return msg;
+}
+
+DBusMessage *
+e_notify_marshal_get_capabilities_return(DBusMessage *method_call, const char **capabilities)
+{
+   DBusMessage *msg;
+   DBusMessageIter iter;
+
+   msg = dbus_message_new_method_return(method_call);
+   dbus_message_iter_init_append(msg, &iter);
+   e_notify_marshal_string_array(&iter, capabilities);
+
+   return msg;
+}
+
+void *
+e_notify_unmarshal_get_capabilities_return(DBusMessage *msg, DBusError *err)
+{
+   DBusMessageIter iter;
+   E_Notification_Return_Get_Capabilities *ret;
+
+   if (!dbus_message_has_signature(msg, "as")) return NULL;
+
+   ret = calloc(1, sizeof(E_Notification_Return_Get_Capabilities));
+   dbus_message_iter_init(msg, &iter);
+   ret->capabilities = e_notify_unmarshal_string_array_as_list(&iter, err);
+
+   return ret;
+}
+
+void
+e_notify_free_get_capabilities_return(void *data)
+{
+   E_Notification_Return_Get_Capabilities *ret = data;
+
+   if (!ret) return;
+   eina_list_free(ret->capabilities);
+   free(ret);
+}
+
+DBusMessage *
+e_notify_marshal_get_server_information()
+{
+   DBusMessage *msg;
+
+   msg = e_notification_call_new("GetServerInformation");
+   return msg;
+}
+
+DBusMessage *
+e_notify_marshal_get_server_information_return(DBusMessage *method_call, const char *name, const char *vendor, const char *version, const char *spec_version)
+{
+   DBusMessage *msg;
+   msg = dbus_message_new_method_return(method_call);
+   dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &vendor, DBUS_TYPE_STRING, &version, DBUS_TYPE_STRING, &spec_version, DBUS_TYPE_INVALID);
+   return msg;
+}
+
+void *
+e_notify_unmarshal_get_server_information_return(DBusMessage *msg, DBusError *err)
+{
+   E_Notification_Return_Get_Server_Information *info;
+   if (dbus_message_has_signature(msg, "ssss"))
+     {
+        info = calloc(1, sizeof(E_Notification_Return_Get_Server_Information));
+        dbus_message_get_args(msg, err,
+                              DBUS_TYPE_STRING, &(info->name),
+                              DBUS_TYPE_STRING, &(info->vendor),
+                              DBUS_TYPE_STRING, &(info->version),
+                              DBUS_TYPE_STRING, &(info->spec_version),
+                              DBUS_TYPE_INVALID
+                              );
+     }
+   else if (dbus_message_has_signature(msg, "sss"))
+     {
+        // stay combatible with servers <= 0.9 spec
+        info = calloc(1, sizeof(E_Notification_Return_Get_Server_Information));
+        dbus_message_get_args(msg, err,
+                              DBUS_TYPE_STRING, &(info->name),
+                              DBUS_TYPE_STRING, &(info->vendor),
+                              DBUS_TYPE_STRING, &(info->version),
+                              DBUS_TYPE_INVALID
+                              );
+     }
+   else
+     {
+        return NULL;
+     }
+   if (dbus_error_is_set(err))
+     {
+        free(info);
+        return NULL;
+     }
+   return info;
+}
+
+void
+e_notify_free_get_server_information_return(void *data)
+{
+   E_Notification_Return_Get_Server_Information *info = data;
+
+   if (!info) return;
+   free(info);
+}
+
+DBusMessage *
+e_notify_marshal_close_notification(dbus_uint32_t id)
+{
+   DBusMessage *msg;
+
+   msg = e_notification_call_new("CloseNotification");
+   dbus_message_append_args(msg, DBUS_TYPE_UINT32, &id, DBUS_TYPE_INVALID);
+   return msg;
+}
+
+dbus_uint32_t
+e_notify_unmarshal_close_notification(DBusMessage *msg, DBusError *err)
+{
+   dbus_uint32_t id;
+   if (!dbus_message_has_signature(msg, "u")) return 0;
+   dbus_message_get_args(msg, err, DBUS_TYPE_UINT32, &id, DBUS_TYPE_INVALID);
+   if (err && dbus_error_is_set(err))
+     return 0;
+
+   return id;
+}
+
+DBusMessage *
+e_notify_marshal_notification_closed_signal(dbus_uint32_t id, dbus_uint32_t reason)
+{
+   DBusMessage *msg;
+   msg = dbus_message_new_signal(E_NOTIFICATION_PATH, E_NOTIFICATION_INTERFACE, "NotificationClosed");
+   dbus_message_append_args(msg, DBUS_TYPE_UINT32, &id, DBUS_TYPE_UINT32, &reason, DBUS_TYPE_INVALID);
+   return msg;
+}
+
+E_Notification_Event_Notification_Closed *
+e_notify_unmarshal_notification_closed_signal(DBusMessage *msg, DBusError *err)
+{
+   E_Notification_Event_Notification_Closed *ev;
+
+   if (!dbus_message_has_signature(msg, "uu"))
+     {
+        dbus_set_error(err, DBUS_ERROR_INVALID_SIGNATURE, "");
+        return NULL;
+     }
+   ev = calloc(1, sizeof(E_Notification_Event_Notification_Closed));
+   dbus_message_get_args(msg, err, DBUS_TYPE_UINT32, &(ev->notification_id), DBUS_TYPE_UINT32, &(ev->reason), DBUS_TYPE_INVALID);
+   if (dbus_error_is_set(err))
+     {
+        free(ev);
+        return NULL;
+     }
+   return ev;
+}
+
+DBusMessage *
+e_notify_marshal_action_invoked_signal(dbus_uint32_t id, const char *action_id)
+{
+   DBusMessage *msg;
+   msg = dbus_message_new_signal(E_NOTIFICATION_PATH, E_NOTIFICATION_INTERFACE, "ActionInvoked");
+   dbus_message_append_args(msg, DBUS_TYPE_UINT32, &id, DBUS_TYPE_STRING, &action_id, DBUS_TYPE_INVALID);
+   return msg;
+}
+
+E_Notification_Event_Action_Invoked *
+e_notify_unmarshal_action_invoked_signal(DBusMessage *msg, DBusError *err)
+{
+   E_Notification_Event_Action_Invoked *ev;
+
+   if (!dbus_message_has_signature(msg, "us"))
+     {
+        dbus_set_error(err, DBUS_ERROR_INVALID_SIGNATURE, "");
+        return NULL;
+     }
+   ev = calloc(1, sizeof(E_Notification_Event_Action_Invoked));
+   dbus_message_get_args(msg, err, DBUS_TYPE_UINT32, &(ev->notification_id), DBUS_TYPE_STRING, &(ev->action_id), DBUS_TYPE_INVALID);
+   if (dbus_error_is_set(err))
+     {
+        free(ev);
+        return NULL;
+     }
+   return ev;
+}
+
+DBusMessage *
+e_notify_marshal_notify(E_Notification *n)
+{
+   DBusMessage *msg;
+   DBusMessageIter iter, sub;
+   Eina_List *l;
+
+   if (!n->app_name) n->app_name = eina_stringshare_add("");
+   if (!n->app_icon) n->app_icon = eina_stringshare_add("");
+   if (!n->summary) n->summary = eina_stringshare_add("");
+   if (!n->body) n->body = eina_stringshare_add("");
+
+   msg = e_notification_call_new("Notify");
+   dbus_message_append_args(msg,
+                            DBUS_TYPE_STRING, &(n->app_name),
+                            DBUS_TYPE_UINT32, &(n->replaces_id),
+                            DBUS_TYPE_STRING, &(n->app_icon),
+                            DBUS_TYPE_STRING, &(n->summary),
+                            DBUS_TYPE_STRING, &(n->body),
+                            DBUS_TYPE_INVALID
+                            );
+
+   dbus_message_iter_init_append(msg, &iter);
+   if (dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
+     {
+        if (n->actions)
+          {
+             E_Notification_Action *action;
+             EINA_LIST_FOREACH (n->actions, l, action)
+               {
+                  dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &(action->id));
+                  dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &(action->name));
+               }
+          }
+        dbus_message_iter_close_container(&iter, &sub);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+
+   /* hints */
+   if (dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
+     {
+        if (n->hints.urgency) /* we only need to send this if its non-zero*/
+          e_notify_marshal_dict_byte(&sub, "urgency", n->hints.urgency);
+        if (n->hints.category)
+          e_notify_marshal_dict_string(&sub, "category", n->hints.category);
+        if (n->hints.desktop)
+          e_notify_marshal_dict_string(&sub, "desktop_entry", n->hints.desktop);
+        if (n->hints.image_data)
+          e_notify_marshal_dict_variant(&sub, "image-data", "(iiibiiay)", E_DBUS_VARIANT_MARSHALLER(e_notify_marshal_hint_image), n->hints.image_data);
+        if (n->hints.sound_file)
+          e_notify_marshal_dict_string(&sub, "sound-file", n->hints.sound_file);
+        if (n->hints.suppress_sound) /* we only need to send this if its true */
+          e_notify_marshal_dict_byte(&sub, "suppress-sound", n->hints.suppress_sound);
+        if (n->hints.x > -1 && n->hints.y > -1)
+          {
+             e_notify_marshal_dict_int(&sub, "x", n->hints.x);
+             e_notify_marshal_dict_int(&sub, "y", n->hints.y);
+          }
+        dbus_message_iter_close_container(&iter, &sub);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+   dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &(n->expire_timeout));
+   return msg;
+}
+
+E_Notification *
+e_notify_unmarshal_notify(DBusMessage *msg, DBusError *err __UNUSED__)
+{
+   E_Notification *n;
+   const char *s_val;
+   dbus_uint32_t u_val;
+   dbus_int32_t i_val;
+   DBusMessageIter iter;
+   if (!dbus_message_has_signature(msg, "susssasa{sv}i")) return NULL;
+
+   n = e_notification_new();
+   if (!n) return NULL;
+   dbus_message_iter_init(msg, &iter);
+
+   dbus_message_iter_get_basic(&iter, &s_val);
+   e_notification_app_name_set(n, s_val);
+   dbus_message_iter_next(&iter);
+
+   dbus_message_iter_get_basic(&iter, &u_val);
+   e_notification_replaces_id_set(n, u_val);
+   dbus_message_iter_next(&iter);
+
+   dbus_message_iter_get_basic(&iter, &s_val);
+   e_notification_app_icon_set(n, s_val);
+   dbus_message_iter_next(&iter);
+
+   dbus_message_iter_get_basic(&iter, &s_val);
+   e_notification_summary_set(n, s_val);
+   dbus_message_iter_next(&iter);
+
+   dbus_message_iter_get_basic(&iter, &s_val);
+   e_notification_body_set(n, s_val);
+   dbus_message_iter_next(&iter);
+
+   e_notify_unmarshal_notify_actions(n, &iter);
+   dbus_message_iter_next(&iter);
+
+   e_notify_unmarshal_notify_hints(n, &iter);
+   dbus_message_iter_next(&iter);
+
+   dbus_message_iter_get_basic(&iter, &i_val);
+   e_notification_timeout_set(n, i_val);
+
+   return n;
+}
+
+DBusMessage *
+e_notify_marshal_notify_return(DBusMessage *method_call, dbus_uint32_t notification_id)
+{
+   DBusMessage *msg;
+   msg = dbus_message_new_method_return(method_call);
+   dbus_message_append_args(msg, DBUS_TYPE_UINT32, &notification_id, DBUS_TYPE_INVALID);
+   return msg;
+}
+
+void *
+e_notify_unmarshal_notify_return(DBusMessage *msg, DBusError *err)
+{
+   E_Notification_Return_Notify *ret;
+   ret = calloc(1, sizeof(E_Notification_Return_Notify));
+   dbus_message_get_args(msg, err, DBUS_TYPE_UINT32, &(ret->notification_id), DBUS_TYPE_INVALID);
+   if (dbus_error_is_set(err))
+     {
+        free(ret);
+        return NULL;
+     }
+   return ret;
+}
+
+void
+e_notify_free_notify_return(void *data)
+{
+   E_Notification_Return_Notify *ret = data;
+
+   if (!ret) return;
+   free(ret);
+}
+
+void
+e_notify_unmarshal_notify_actions(E_Notification *n, DBusMessageIter *iter)
+{
+   DBusMessageIter arr;
+   const char *id, *name;
+   dbus_message_iter_recurse(iter, &arr);
+   while (dbus_message_iter_has_next(&arr))
+     {
+        dbus_message_iter_get_basic(&arr, &id);
+        dbus_message_iter_next(&arr);
+        dbus_message_iter_get_basic(&arr, &name);
+        dbus_message_iter_next(&arr);
+        e_notification_action_add(n, id, name);
+     }
+}
+
+void
+e_notify_unmarshal_notify_hints(E_Notification *n, DBusMessageIter *iter)
+{
+   DBusMessageIter arr;
+   const char *key;
+   int x_set = 0, y_set = 0;
+   int x, y;
+   dbus_message_iter_recurse(iter, &arr);
+
+   if (dbus_message_iter_get_arg_type(&arr) == DBUS_TYPE_INVALID)
+     return;
+
+   do
+     {
+        DBusMessageIter dict;
+        dbus_message_iter_recurse(&arr, &dict);
+        do
+          {
+             DBusMessageIter variant;
+             const char *s_val;
+             char y_val;
+             dbus_bool_t b_val;
+
+             dbus_message_iter_get_basic(&dict, &key);
+             dbus_message_iter_next(&dict);
+             dbus_message_iter_recurse(&dict, &variant);
+
+             if (!strcmp(key, "urgency"))
+               {
+                  dbus_message_iter_get_basic(&variant, &y_val);
+                  e_notification_hint_urgency_set(n, y_val);
+               }
+             else if (!strcmp(key, "category"))
+               {
+                  dbus_message_iter_get_basic(&variant, &s_val);
+                  e_notification_hint_category_set(n, s_val);
+               }
+             else if (!strcmp(key, "desktop-entry"))
+               {
+                  dbus_message_iter_get_basic(&variant, &s_val);
+                  e_notification_hint_desktop_set(n, s_val);
+               }
+             else if ((!strncmp(key, "image", 5)))
+               {
+                  if ((key[5] != '-') && (key[5] != '_')) continue;
+                  if (!strcmp(key + 6, "path"))
+                    {
+                       dbus_message_iter_get_basic(&variant, &s_val);
+                       e_notification_hint_image_path_set(n, s_val);
+                    }
+                  else if (!strcmp(key + 6, "data"))
+                    {
+                       dbus_message_iter_recurse(&dict, &variant);
+                       n->hints.image_data = e_notify_unmarshal_hint_image(&variant);
+                    }
+               }
+             else if (!strcmp(key, "sound-file"))
+               {
+                  dbus_message_iter_get_basic(&variant, &s_val);
+                  e_notification_hint_sound_file_set(n, s_val);
+               }
+             else if (!strcmp(key, "suppress-sound"))
+               {
+                  dbus_message_iter_get_basic(&variant, &b_val);
+                  e_notification_hint_suppress_sound_set(n, b_val);
+               }
+             else if (!strcmp(key, "transient"))
+               {
+                  dbus_message_iter_get_basic(&variant, &b_val);
+                  e_notification_hint_transient_set(n, b_val);
+               }
+             else if (!strcmp(key, "resident"))
+               {
+                  dbus_message_iter_get_basic(&variant, &b_val);
+                  e_notification_hint_resident_set(n, b_val);
+               }
+             else if (!strcmp(key, "x"))
+               {
+                  dbus_message_iter_get_basic(&variant, &x);
+                  x_set = 1;
+               }
+             else if (!strcmp(key, "y"))
+               {
+                  dbus_message_iter_get_basic(&variant, &y);
+                  y_set = 1;
+               }
+             else if (!strcmp(key, "icon_data"))
+               {
+                  dbus_message_iter_recurse(&dict, &variant);
+                  n->hints.icon_data = e_notify_unmarshal_hint_image(&variant);
+               }
+          }
+        while (dbus_message_iter_next(&dict));
+     }
+   while (dbus_message_iter_next(&arr));
+
+   if (x_set && y_set)
+     e_notification_hint_xy_set(n, x, y);
+}
+
+void
+e_notify_marshal_hint_image(DBusMessageIter *iter, E_Notification_Image *img)
+{
+   DBusMessageIter sub, arr;
+   int data_len = 0;
+
+   data_len = ((img->height - 1) * img->rowstride) + (img->width * (((img->channels * img->bits_per_sample) + 7) / 8));
+   if (dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &sub))
+     {
+        dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &(img->width));
+        dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &(img->height));
+        dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &(img->rowstride));
+        dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &(img->has_alpha));
+        dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &(img->bits_per_sample));
+        dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &(img->channels));
+        if (dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "y", &arr))
+          {
+             dbus_message_iter_append_fixed_array(&arr, DBUS_TYPE_BYTE, &(img->data), data_len);
+             dbus_message_iter_close_container(&sub, &arr);
+          }
+        else
+          {
+             ERR("dbus_message_iter_open_container() failed");
+          }
+        dbus_message_iter_close_container(iter, &sub);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+}
+
+E_Notification_Image *
+e_notify_unmarshal_hint_image(DBusMessageIter *iter)
+{
+   DBusMessageIter sub, arr;
+   char *byte_array;
+   int array_len;
+   E_Notification_Image *img;
+   char *sig;
+   int sig_matches;
+
+   sig = dbus_message_iter_get_signature(iter);
+   sig_matches = strcmp(sig, "(iiibiiay)");
+   dbus_free(sig);
+   if (sig_matches) return NULL;
+
+   img = e_notification_image_new();
+   if (!img) return NULL;
+
+   dbus_message_iter_recurse(iter, &sub);
+   dbus_message_iter_get_basic(&sub, &(img->width));
+   dbus_message_iter_next(&sub);
+   dbus_message_iter_get_basic(&sub, &(img->height));
+   dbus_message_iter_next(&sub);
+   dbus_message_iter_get_basic(&sub, &(img->rowstride));
+   dbus_message_iter_next(&sub);
+   dbus_message_iter_get_basic(&sub, &(img->has_alpha));
+   dbus_message_iter_next(&sub);
+   dbus_message_iter_get_basic(&sub, &(img->bits_per_sample));
+   dbus_message_iter_next(&sub);
+   dbus_message_iter_get_basic(&sub, &(img->channels));
+   dbus_message_iter_next(&sub);
+
+   dbus_message_iter_recurse(&sub, &arr);
+   dbus_message_iter_get_fixed_array(&arr, &(byte_array), &array_len);
+   img->data = malloc(array_len);
+   memcpy(img->data, byte_array, array_len);
+
+   return img;
+}
+
diff --git a/src/lib/notification/notification-spec.xml b/src/lib/notification/notification-spec.xml
new file mode 100644 (file)
index 0000000..2923fa1
--- /dev/null
@@ -0,0 +1,1277 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS/DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
+<article id="index">
+ <articleinfo>
+  <title>Desktop Notifications Specification</title>
+  <releaseinfo>Version 1.2</releaseinfo>
+  <date>28 October 2010</date>
+  <authorgroup>
+   <author>
+    <firstname>Mike</firstname>
+    <surname>Hearn</surname>
+    <affiliation>
+     <address>
+      <email>mike@navi.cx</email>
+     </address>
+    </affiliation>
+   </author>
+   <author>
+    <firstname>Christian</firstname>
+    <surname>Hammond</surname>
+    <affiliation>
+     <address>
+      <email>chipx86@chipx86.com</email>
+     </address>
+    </affiliation>
+   </author>
+   <author>
+    <firstname>William Jon</firstname>
+    <surname>McCann</surname>
+    <affiliation>
+     <address>
+      <email>jmccann@redhat.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+ </articleinfo>
+
+ <sect1 id="introduction">
+  <title>Introduction</title>
+  <para>
+   This is a draft standard for a desktop notifications service,
+   through which applications can generate passive popups to notify
+   the user in an asynchronous manner of events.
+  </para>
+  <para>
+   This specification explicitly does not include other types of
+   notification presentation such as modal message boxes, window manager
+   decorations or window list annotations.
+  </para>
+  <para>
+   Example use cases include:
+  </para>
+  <itemizedlist>
+   <listitem><para>Messages from chat programs</para> </listitem>
+   <listitem><para>Scheduled alarm</para></listitem>
+   <listitem><para>Completed file transfer</para></listitem>
+   <listitem><para>New mail notification</para></listitem>
+   <listitem><para>Low disk space/battery warnings</para></listitem>
+  </itemizedlist>
+ </sect1>
+
+ <sect1 id="basic-design">
+  <title>Basic Design</title>
+  <para>
+   In order to ensure that multiple notifications can easily be
+   displayed at once, and to provide a convenient implementation, all
+   notifications are controlled by a single session-scoped service which
+   exposes a D-BUS interface.
+  </para>
+  <para>
+   On startup, a conforming implementation should take the
+   <literal>org.freedesktop.Notifications</literal> service on
+   the session bus. This service will be referred to as the "notification
+   server" or just "the server" in this document. It can optionally be
+   activated automatically by the bus process, however this is not required
+   and notification server clients must not assume that it is available.
+  </para>
+  <para>
+   The server should implement the
+   <literal>org.freedesktop.Notifications</literal> interface on
+   an object with the path <literal>"/org/freedesktop/Notifications"</literal>.
+   This is the only interface required by this version of the specification.
+  </para>
+  <para>
+   A notification has the following components:
+  </para>
+  <table>
+   <title>Notification Components</title>
+   <tgroup cols="2">
+    <thead>
+     <row>
+      <entry>Component</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+    <tbody valign="top">
+     <row>
+      <entry>Application Name</entry>
+      <entry>
+       This is the optional name of the application sending the notification.
+       This should be the application's formal name, rather than some sort
+       of ID. An example would be "FredApp E-Mail Client," rather than
+       "fredapp-email-client."
+      </entry>
+     </row>
+     <row>
+      <entry>Replaces ID</entry>
+      <entry>
+       An optional ID of an existing notification that this
+       notification is intended to replace.
+      </entry>
+     </row>
+     <row>
+      <entry>Notification Icon</entry>
+      <entry>
+        The notification icon. See <xref linkend="icons-and-images-formats"/>.
+      </entry>
+     </row>
+     <row>
+      <entry>Summary</entry>
+      <entry>
+       This is a single line overview of the notification. For instance,
+       "You have mail" or "A friend has come online". It should generally
+       not be longer than 40 characters, though this is not a requirement,
+       and server implementations should word wrap if necessary. The summary
+       must be encoded using UTF-8.
+      </entry>
+     </row>
+     <row>
+      <entry>Body</entry>
+      <entry>
+       <para>
+        This is a multi-line body of text. Each line is a paragraph, server
+        implementations are free to word wrap them as they see fit.
+       </para>
+       <para>
+        The body may contain simple markup as specified in
+        <xref linkend="markup"/>. It must be encoded using UTF-8.
+       </para>
+       <para>
+        If the body is omitted, just the summary is displayed.
+       </para>
+      </entry>
+     </row>
+     <row>
+      <entry>Actions</entry>
+      <entry>
+       <para>
+        The actions send a request message back to the notification client
+        when invoked. This functionality may not be implemented by the
+        notification server, conforming clients should check if it is available
+        before using it (see the GetCapabilities message in
+        <xref linkend="protocol"/>). An implementation is free to ignore any
+        requested by the client. As an example one possible rendering of
+        actions would be as buttons in the notification popup.
+       </para>
+       <para>
+        Actions are sent over as a list of pairs. Each even element in the
+        list (starting at index 0) represents the identifier for the action.
+        Each odd element in the list is the localized string that will be
+        displayed to the user.
+       </para>
+       <para>
+        The default action (usually invoked my clicking the notification)
+        should have a key named <literal>"default"</literal>. The name can
+        be anything, though implementations are free not to display it.
+       </para>
+      </entry>
+     </row>
+     <row>
+      <entry>Hints</entry>
+      <entry>
+       <para>
+        Hints are a way to provide extra data to a notification server that
+        the server may be able to make use of.
+       </para>
+       <para>See <xref linkend="hints"/> for a list of available hints.</para>
+      </entry>
+     </row>
+     <row>
+      <entry>Expiration Timeout</entry>
+      <entry>
+       <para>
+        The timeout time in milliseconds since the display of the notification
+        at which the notification should automatically close.
+       </para>
+       <para>
+        If -1, the notification's expiration time is dependent on the
+        notification server's settings, and may vary for the type of
+        notification.
+       </para>
+       <para>
+        If 0, the notification never expires.
+       </para>
+      </entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+  <para>
+   Each notification displayed is allocated a unique ID by the server.
+   This is unique within the session. While the notification server is
+   running, the ID will not be recycled unless the capacity of a uint32 is
+   exceeded.
+  </para>
+  <para>
+   This can be used to hide the notification before the expiration timeout
+   is reached. It can also be used to atomically replace the notification
+   with another. This allows you to (for instance) modify the contents of
+   a notification while it's on-screen.
+  </para>
+ </sect1>
+
+ <sect1 id="backwards-compat" xreflabel="Backwards Compatibility">
+  <title>Backwards Compatibility</title>
+  <para>
+   Clients should try and avoid making assumptions about the presentation and
+   abilities of the notification server. The message content is the most
+   important thing.
+  </para>
+  <para>
+   Clients can check with the server what capabilities are supported
+   using the <literal>GetCapabilities</literal> message. See
+   <xref linkend="protocol"/>.
+  </para>
+  <para>
+   If a client requires a response from a passive popup, it should be
+   coded such that a non-focus-stealing message box can be used in the
+   case that the notification server does not support this feature.
+  </para>
+ </sect1>
+
+ <sect1 id="markup" xreflabel="Markup">
+  <title>Markup</title>
+  <para>
+   Body text may contain markup. The markup is XML-based, and consists
+   of a small subset of HTML along with a few additional tags.
+  </para>
+  <para>
+   The following tags should be supported by the notification server.
+   Though it is optional, it is recommended. Notification servers that do
+   not support these tags should filter them out.
+  </para>
+  <informaltable>
+   <tgroup cols="2">
+    <tbody valign="top">
+     <row>
+      <entry>
+       <sgmltag class="starttag">b</sgmltag> ...
+       <sgmltag class="endtag">b</sgmltag>
+      </entry>
+      <entry>Bold</entry>
+     </row>
+     <row>
+      <entry>
+       <sgmltag class="starttag">i</sgmltag> ...
+       <sgmltag class="endtag">i</sgmltag>
+      </entry>
+      <entry>Italic</entry>
+     </row>
+     <row>
+      <entry>
+       <sgmltag class="starttag">u</sgmltag> ...
+       <sgmltag class="endtag">u</sgmltag>
+      </entry>
+      <entry>Underline</entry>
+     </row>
+     <row>
+      <entry>
+       <sgmltag class="starttag">a href="..."</sgmltag> ...
+       <sgmltag class="endtag">a</sgmltag>
+      </entry>
+      <entry>Hyperlink</entry>
+     </row>
+     <row>
+      <entry>
+       <sgmltag class="emptytag">img src="..." alt="..."</sgmltag>
+      </entry>
+      <entry>Image</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </informaltable>
+  <para>
+   A full-blown HTML implementation is not required of this spec, and
+   notifications should never take advantage of tags that are not listed
+   above. As notifications are not a substitute for web browsers or complex
+   dialogs, advanced layout is not necessary, and may in fact limit the
+   number of systems that notification services can run on, due to memory
+   usage and screen space. Such examples are PDAs, certain cell phones, and
+   slow PCs or laptops with little memory.
+  </para>
+  <para>
+   For the same reason, a full XML or XHTML implementation using XSLT or
+   CSS stylesheets is not part of this specification. Information that
+   must be presented in a more complex form should use an application-specific
+   dialog, a web browser, or some other display mechanism.
+  </para>
+  <para>
+   The tags specified above mark up the content in a way that allows them
+   to be stripped out on some implementations without impacting the actual
+   content.
+  </para>
+
+  <sect2 id="hyperlinks" xreflabel="Hyperlinks">
+   <title>Hyperlinks</title>
+   <para>
+    Hyperlinks allow for linking one or more words to a URI. There is no
+    requirement to allow for images to be linked, and it is highly suggested
+    that implementations do not allow this, as there is no clean-looking,
+    standard visual indicator for a hyperlinked image.
+   </para>
+   <para>
+    Hyperlinked text should appear in the standard blue underline format.
+   </para>
+   <para>
+    Hyperlinks cannot function as a replacement for actions. They are
+    used to link to local directories or remote sites using standard URI
+    schemes.
+   </para>
+   <para>
+    Implementations are not required to support hyperlinks.
+   </para>
+  </sect2>
+
+  <sect2 id="images" xreflabel="Images">
+   <title>Images</title>
+   <para>
+    Images may be placed in the notification, but this should be done with
+    caution. The image should never exceed 200x100, but this should be thought
+    of as a maximum size. Images should always have alternative text
+    provided through the <literal>alt="..."</literal> attribute.
+   </para>
+   <para>
+    Image data cannot be embedded in the message itself. Images referenced
+    must always be local files.
+   </para>
+   <para>
+    Implementations are not required to support images.
+   </para>
+  </sect2>
+ </sect1>
+
+ <sect1 id="icons-and-images" xreflabel="Icons and Images">
+  <title>Icons and Images</title>
+  <para>
+   A notification can optionally have an associated icon and/or image.
+  </para>
+  <para>
+   The icon is defined by the "app_icon" parameter.
+   The image can be defined by the "image-path", the "image-data" hint or the
+   deprecated "icon_data" hint.
+  </para>
+  <sect2>
+   <title>Priorities</title>
+   <para>
+    An implementation which only displays one image or icon must choose which one
+    to display using the following order:
+    <orderedlist>
+     <listitem><para>"image-data"</para></listitem>
+     <listitem><para>"image-path"</para></listitem>
+     <listitem><para>app_icon parameter</para></listitem>
+     <listitem><para>for compatibility reason, "icon_data"</para></listitem>
+    </orderedlist>
+   </para>
+
+   <para>
+    An implementation which can display both the image and icon must show the
+    icon from the "app_icon" parameter and choose which image to display using
+    the following order:
+    <orderedlist>
+     <listitem><para>"image-data"</para></listitem>
+     <listitem><para>"image-path"</para></listitem>
+     <listitem><para>for compatibility reason, "icon_data"</para></listitem>
+    </orderedlist>
+   </para>
+  </sect2>
+
+  <sect2 id="icons-and-images-formats" xreflabel="Icons and Images Formats">
+   <title>Formats</title>
+   <para>
+    The "image-data" and "icon_data" hints should be a DBus structure
+    of signature (iiibiiay).  The components of this structure are as follows:
+    <orderedlist>
+     <listitem><para>width (i): Width of image in pixels</para></listitem>
+     <listitem><para>height (i): Height of image in pixels</para></listitem>
+     <listitem><para>rowstride (i): Distance in bytes between row starts</para></listitem>
+     <listitem><para>has_alpha (b): Whether the image has an alpha channel</para></listitem>
+     <listitem><para>bits_per_sample (i): Must always be 8</para></listitem>
+     <listitem><para>channels (i): If has_alpha is TRUE, must be 4, otherwise 3</para></listitem>
+     <listitem><para>data (ay): The image data, in RGB byte order</para></listitem>
+    </orderedlist>
+    This image format is derived from <ulink url="http://developer.gnome.org/gdk-pixbuf/stable/">gdk-pixbuf</ulink>.
+  </para>
+   <para>
+    The "app_icon" parameter and "image-path" hint should be either an URI
+    (file:// is the only URI schema supported right now) or a name in a
+    freedesktop.org-compliant icon theme (not a GTK+ stock ID).
+   </para>
+  </sect2>
+ </sect1>
+
+ <sect1 id="categories" xreflabel="Categories">
+  <title>Categories</title>
+  <para>
+   Notifications can optionally have a type indicator. Although neither
+   client or nor server must support this, some may choose to. Those servers
+   implementing categories may use them to intelligently display
+   the notification in a certain way, or group notifications of similar
+   types.
+  </para>
+  <para>
+   Categories are in
+   <literal><replaceable>class.specific</replaceable></literal> form.
+   <literal>class</literal> specifies the generic type of notification, and
+   <literal>specific</literal> specifies the more specific type of
+   notification.
+  </para>
+  <para>
+   If a specific type of notification does not exist for your notification,
+   but the generic kind does, a notification of type
+   <literal><replaceable>class</replaceable></literal> is acceptable.
+  </para>
+  <para>
+   Third parties, when defining their own categories, should discuss
+   the possibility of standardizing on the hint with other parties, preferably
+   in a place such as the
+   <ulink url="http://freedesktop.org/mailman/listinfo/xdg">xdg</ulink>
+   mailing list at
+   <ulink url="http://freedesktop.org/">freedesktop.org</ulink>. If it
+   warrants a standard, it will be added to the table above. If no
+   consensus is reached, the category should be in the form of
+   "<literal>x-<replaceable>vendor</replaceable>.<replaceable>class</replaceable>.<replaceable>name</replaceable></literal>."
+  </para>
+  <para>
+   The following table lists standard notifications as defined by this spec.
+   More will be added in time.
+  </para>
+  <table>
+   <title>Categories</title>
+   <tgroup cols="2">
+    <thead>
+     <row>
+      <entry>Type</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+    <tbody valign="top">
+     <row>
+      <entry><literal>"device"</literal></entry>
+      <entry>
+       A generic device-related notification that doesn't fit into
+       any other category.
+      </entry>
+     </row>
+     <row>
+      <entry><literal>"device.added"</literal></entry>
+      <entry>A device, such as a USB device, was added to the system.</entry>
+     </row>
+     <row>
+      <entry><literal>"device.error"</literal></entry>
+      <entry>A device had some kind of error.</entry>
+     </row>
+     <row>
+      <entry><literal>"device.removed"</literal></entry>
+      <entry>
+       A device, such as a USB device, was removed from the system.
+      </entry>
+     </row>
+     <row>
+      <entry><literal>"email"</literal></entry>
+      <entry>
+       A generic e-mail-related notification that doesn't fit into any
+       other category.
+      </entry>
+     </row>
+     <row>
+      <entry><literal>"email.arrived"</literal></entry>
+      <entry>A new e-mail notification.</entry>
+     </row>
+     <row>
+      <entry><literal>"email.bounced"</literal></entry>
+      <entry>A notification stating that an e-mail has bounced.</entry>
+     </row>
+     <row>
+      <entry><literal>"im"</literal></entry>
+      <entry>
+       A generic instant message-related notification that doesn't fit
+       into any other category.
+      </entry>
+     </row>
+     <row>
+      <entry><literal>"im.error"</literal></entry>
+      <entry>An instant message error notification.</entry>
+     </row>
+     <row>
+      <entry><literal>"im.received"</literal></entry>
+      <entry>A received instant message notification.</entry>
+     </row>
+     <row>
+      <entry><literal>"network"</literal></entry>
+      <entry>
+       A generic network notification that doesn't fit into any other
+       category.
+      </entry>
+     </row>
+     <row>
+      <entry><literal>"network.connected"</literal></entry>
+      <entry>
+       A network connection notification, such as successful sign-on to a
+       network service. This should not be confused with
+       <literal>device.added</literal> for new network devices.
+      </entry>
+     </row>
+     <row>
+      <entry><literal>"network.disconnected"</literal></entry>
+      <entry>
+       A network disconnected notification. This should not be confused with
+       <literal>device.removed</literal> for disconnected network devices.
+      </entry>
+     </row>
+     <row>
+      <entry><literal>"network.error"</literal></entry>
+      <entry>
+       A network-related or connection-related error.
+      </entry>
+     </row>
+     <row>
+      <entry><literal>"presence"</literal></entry>
+      <entry>
+       A generic presence change notification that doesn't fit into
+       any other category, such as going away or idle.
+      </entry>
+     </row>
+     <row>
+      <entry><literal>"presence.offline"</literal></entry>
+      <entry>An offline presence change notification.</entry>
+     </row>
+     <row>
+      <entry><literal>"presence.online"</literal></entry>
+      <entry>An online presence change notification.</entry>
+     </row>
+     <row>
+      <entry><literal>"transfer"</literal></entry>
+      <entry>
+       A generic file transfer or download notification that doesn't fit
+       into any other category.
+      </entry>
+     </row>
+     <row>
+      <entry><literal>"transfer.complete"</literal></entry>
+      <entry>A file transfer or download complete notification.</entry>
+     </row>
+     <row>
+      <entry><literal>"transfer.error"</literal></entry>
+      <entry>A file transfer or download error.</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+ </sect1>
+
+ <sect1 id="urgency-levels" xreflabel="Urgency Levels">
+  <title>Urgency Levels</title>
+  <para>
+   Notifications have an urgency level associated with them. This defines
+   the importance of the notification. For example, "Joe Bob signed on"
+   would be a low urgency. "You have new mail" or "A USB device was unplugged"
+   would be a normal urgency. "Your computer is on fire" would be a critical
+   urgency.
+  </para>
+  <para>Urgency levels are defined as follows:</para>
+  <table>
+   <title>Urgency Levels</title>
+   <tgroup cols="2">
+    <thead>
+     <row>
+      <entry>Type</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+    <tbody valign="top">
+     <row>
+      <entry>0</entry>
+      <entry>Low</entry>
+     </row>
+     <row>
+      <entry>1</entry>
+      <entry>Normal</entry>
+     </row>
+     <row>
+      <entry>2</entry>
+      <entry>Critical</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+  <para>
+   Developers must use their own judgement when deciding the urgency of a
+   notification. Typically, if the majority of programs are using the same
+   level for a specific type of urgency, other applications should follow
+   them.
+  </para>
+  <para>
+   For low and normal urgencies, server implementations may display the
+   notifications how they choose. They should, however, have a sane
+   expiration timeout dependent on the urgency level.
+  </para>
+  <para>
+   Critical notifications should not automatically expire, as they are
+   things that the user will most likely want to know about. They should
+   only be closed when the user dismisses them, for example, by clicking on
+   the notification.
+  </para>
+ </sect1>
+
+ <sect1 id="hints" xreflabel="Hints">
+  <title>Hints</title>
+  <para>
+   Hints are a way to provide extra data to a notification server that
+   the server may be able to make use of.
+  </para>
+  <para>
+   Neither clients nor notification servers are required to support any
+   hints. Both sides should assume that hints are not passed, and should
+   ignore any hints they do not understand.
+  </para>
+  <para>
+   Third parties, when defining their own hints, should discuss the
+   possibility of standardizing on the hint with other parties, preferably
+   in a place such as the
+   <ulink url="http://freedesktop.org/mailman/listinfo/xdg">xdg</ulink>
+   mailing list at
+   <ulink url="http://freedesktop.org/">freedesktop.org</ulink>. If it
+   warrants a standard, it will be added to the table above. If no
+   consensus is reached, the hint name should be in the form of
+   <literal>"x-<replaceable>vendor</replaceable>-<replaceable>name</replaceable>."</literal>
+  </para>
+  <para>
+   The value type for the hint dictionary in D-BUS is of the
+   <literal>DBUS_TYPE_VARIANT</literal> container type. This allows different
+   data types (string, integer, boolean, etc.) to be used for hints. When
+   adding a dictionary of hints, this type must be used, rather than putting
+   the actual hint value in as the dictionary value.
+  </para>
+  <para>
+   The following table lists the standard hints as defined by this
+   specification. Future hints may be proposed and added to this list
+   over time. Once again, implementations are not required to support these.
+  </para>
+  <table>
+   <title>Standard Hints</title>
+   <tgroup cols="2">
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Value Type</entry>
+      <entry>Description</entry>
+      <entry>Spec Version</entry>
+     </row>
+    </thead>
+    <tbody valign="top">
+     <row>
+      <entry><literal>"action-icons"</literal></entry>
+      <entry>boolean</entry>
+      <entry>
+       When set, a server that has the "action-icons" capability will
+       attempt to interpret any action identifier as a named icon.
+       The localized display name will be used to annotate the icon
+       for accessibility purposes.  The icon name should be compliant
+       with the Freedesktop.org Icon Naming Specification.
+      </entry>
+      <entry>&gt;= 1.2</entry>
+     </row>
+     <row>
+      <entry><literal>"category"</literal></entry>
+      <entry>string</entry>
+      <entry>
+       The type of notification this is.
+      </entry>
+      <entry/>
+     </row>
+     <row>
+      <entry><literal>"desktop-entry"</literal></entry>
+      <entry>string</entry>
+      <entry>
+       This specifies the name of the desktop filename representing the
+       calling program. This should be the same as the prefix used for the
+       application's .desktop file. An example would be "rhythmbox" from
+       "rhythmbox.desktop". This can be used by the daemon to retrieve the
+       correct icon for the application, for logging purposes, etc.
+      </entry>
+      <entry/>
+     </row>
+     <row>
+      <entry><literal>"image-data"</literal></entry>
+      <entry>(iiibiiay)</entry>
+      <entry>
+        This is a raw data image format which describes the width, height,
+        rowstride, has alpha, bits per sample, channels and image data
+        respectively.
+      </entry>
+      <entry>&gt;= 1.2</entry>
+     </row>
+     <row>
+      <entry><literal>"image_data"</literal></entry>
+      <entry>(iiibiiay)</entry>
+      <entry>
+        <emphasis>Deprecated</emphasis>. Use image-data instead.
+      </entry>
+      <entry>= 1.1</entry>
+     </row>
+     <row>
+      <entry><literal>"image-path"</literal></entry>
+      <entry>string</entry>
+      <entry>
+        Alternative way to define the notification image. See <xref linkend="icons-and-images"/>.
+      </entry>
+      <entry>&gt;= 1.2</entry>
+     </row>
+     <row>
+      <entry><literal>"image_path"</literal></entry>
+      <entry>string</entry>
+      <entry>
+        <emphasis>Deprecated</emphasis>. Use image-path instead.
+      </entry>
+      <entry>= 1.1</entry>
+     </row>
+     <row>
+      <entry><literal>"icon_data"</literal></entry>
+      <entry>(iiibiiay)</entry>
+      <entry>
+        <emphasis>Deprecated</emphasis>. Use image-data instead.
+      </entry>
+      <entry>&lt; 1.1</entry>
+     </row>
+     <row>
+      <entry><literal>"resident"</literal></entry>
+      <entry>boolean</entry>
+      <entry>
+       When set the server will not automatically remove the
+       notification when an action has been invoked.  The notification
+       will remain resident in the server until it is explicitly
+       removed by the user or by the sender.  This hint is likely only
+       useful when the server has the "persistence" capability.
+      </entry>
+      <entry>&gt;= 1.2</entry>
+     </row>
+     <row>
+      <entry><literal>"sound-file"</literal></entry>
+      <entry>string</entry>
+      <entry>
+       The path to a sound file to play when the notification pops up.
+      </entry>
+      <entry/>
+     </row>
+     <row>
+      <entry><literal>"sound-name"</literal></entry>
+      <entry>string</entry>
+      <entry>
+       A themeable named sound from the freedesktop.org
+       <ulink url="http://0pointer.de/public/sound-naming-spec.html">sound naming specification</ulink>
+       to play when the notification pops up. Similar to icon-name, only for
+       sounds. An example would be "message-new-instant".
+      </entry>
+      <entry/>
+     </row>
+     <row>
+      <entry><literal>"suppress-sound"</literal></entry>
+      <entry>boolean</entry>
+      <entry>
+       Causes the server to suppress playing any sounds, if it has that
+       ability. This is usually set when the client itself is going to
+       play its own sound.
+      </entry>
+      <entry/>
+     </row>
+     <row>
+      <entry><literal>"transient"</literal></entry>
+      <entry>boolean</entry>
+      <entry>
+       When set the server will treat the notification as transient
+       and by-pass the server's persistence capability, if it should
+       exist.
+      </entry>
+      <entry>&gt;= 1.2</entry>
+     </row>
+     <row>
+      <entry><literal>"x"</literal></entry>
+      <entry>int</entry>
+      <entry>
+       Specifies the X location on the screen that the notification should
+       point to. The <literal>"y"</literal> hint must also be specified.
+      </entry>
+      <entry/>
+     </row>
+     <row>
+      <entry><literal>"y"</literal></entry>
+      <entry>int</entry>
+      <entry>
+       Specifies the Y location on the screen that the notification should
+       point to. The <literal>"x"</literal> hint must also be specified.
+      </entry>
+      <entry/>
+     </row>
+     <row>
+      <entry><literal>"urgency"</literal></entry>
+      <entry>byte</entry>
+      <entry>
+       The urgency level.
+      </entry>
+      <entry/>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+ </sect1>
+
+ <sect1 id="protocol" xreflabel="Protocol">
+  <title>D-BUS Protocol</title>
+  <para>
+   The following messages <emphasis>must</emphasis> be supported by all
+   implementations.
+  </para>
+
+  <sect2 id="commands">
+   <title>Message commands</title>
+
+   <sect3 id="command-get-capabilities">
+    <title><literal>org.freedesktop.Notifications.GetCapabilities</literal></title>
+    <funcsynopsis>
+     <funcprototype>
+      <funcdef>STRING_ARRAY
+       <function>org.freedesktop.Notifications.GetCapabilities</function>
+      </funcdef>
+      <void/>
+     </funcprototype>
+    </funcsynopsis>
+    <para>
+     This message takes no parameters.
+    </para>
+    <para>
+     It returns an array of strings. Each string describes an optional
+     capability implemented by the server. The following values are
+     defined by this spec:
+    </para>
+    <table>
+     <title>Server Capabilities</title>
+     <tgroup cols="2">
+      <tbody valign="top">
+       <row>
+        <entry><literal>"action-icons"</literal></entry>
+        <entry>
+         Supports using icons instead of text for displaying actions.
+         Using icons for actions must be enabled on a per-notification
+         basis using the "action-icons" hint.
+        </entry>
+       </row>
+       <row>
+        <entry><literal>"actions"</literal></entry>
+        <entry>
+         The server will provide the specified actions to the user. Even if
+         this cap is missing, actions may still be specified by the client,
+         however the server is free to ignore them.
+        </entry>
+       </row>
+       <row>
+        <entry><literal>"body"</literal></entry>
+        <entry>
+         Supports body text. Some implementations may only show the
+         summary (for instance, onscreen displays, marquee/scrollers)
+        </entry>
+       </row>
+       <row>
+        <entry><literal>"body-hyperlinks"</literal></entry>
+        <entry>
+         The server supports hyperlinks in the notifications.
+        </entry>
+       </row>
+       <row>
+        <entry><literal>"body-images"</literal></entry>
+        <entry>
+         The server supports images in the notifications.
+        </entry>
+       </row>
+       <row>
+        <entry><literal>"body-markup"</literal></entry>
+        <entry>
+         Supports markup in the body text. If marked up text is sent
+         to a server that does not give this cap, the markup will show
+         through as regular text so must be stripped clientside.
+        </entry>
+       </row>
+       <row>
+        <entry><literal>"icon-multi"</literal></entry>
+        <entry>
+         The server will render an animation of all the frames in a given
+         image array. The client may still specify multiple frames even if
+         this cap and/or <literal>"icon-static"</literal> is missing, however
+         the server is free to ignore them and use only the primary frame.
+        </entry>
+       </row>
+       <row>
+        <entry><literal>"icon-static"</literal></entry>
+        <entry>
+         Supports display of exactly 1 frame of any given image array.
+         This value is mutually exclusive with
+         <literal>"icon-multi"</literal>, it is a protocol error for the
+         server to specify both.
+        </entry>
+       </row>
+       <row>
+        <entry><literal>"persistence"</literal></entry>
+        <entry>
+         The server supports persistence of notifications.
+         Notifications will be retained until they are acknowledged or
+         removed by the user or recalled by the sender.  The presence
+         of this capability allows clients to depend on the server to
+         ensure a notification is seen and eliminate the need for
+         the client to display a reminding function (such as a status
+         icon) of its own.
+        </entry>
+       </row>
+       <row>
+        <entry><literal>"sound"</literal></entry>
+        <entry>
+         The server supports sounds on notifications. If returned, the
+         server must support the <literal>"sound-file"</literal> and
+         <literal>"suppress-sound"</literal> hints.
+        </entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+    <para>
+     New vendor-specific caps may be specified as long as they start with
+     <literal>"x-<replaceable>vendor</replaceable>"</literal>. For instance,
+     <literal>"x-gnome-foo-cap"</literal>. Capability names must not
+     contain spaces. They are limited to alpha-numeric characters and dashes
+     (<literal>"-"</literal>).
+    </para>
+   </sect3>
+
+   <sect3 id="command-notify">
+    <title><literal>org.freedesktop.Notifications.Notify</literal></title>
+    <funcsynopsis>
+     <funcprototype>
+      <funcdef>UINT32
+       <function>org.freedesktop.Notifications.Notify</function>
+      </funcdef>
+      <paramdef>STRING <parameter>app_name</parameter></paramdef>
+      <paramdef>UINT32 <parameter>replaces_id</parameter></paramdef>
+      <paramdef>STRING <parameter>app_icon</parameter></paramdef>
+      <paramdef>STRING <parameter>summary</parameter></paramdef>
+      <paramdef>STRING <parameter>body</parameter></paramdef>
+      <paramdef>ARRAY <parameter>actions</parameter></paramdef>
+      <paramdef>DICT <parameter>hints</parameter></paramdef>
+      <paramdef>INT32 <parameter>expire_timeout</parameter></paramdef>
+     </funcprototype>
+    </funcsynopsis>
+    <para>
+     Sends a notification to the notification server.
+    </para>
+    <table>
+     <title>Notify Parameters</title>
+     <tgroup cols="3">
+      <thead>
+       <row>
+        <entry>Name</entry>
+        <entry>Type</entry>
+        <entry>Description</entry>
+       </row>
+      </thead>
+      <tbody valign="top">
+       <row>
+        <entry><parameter>app_name</parameter></entry>
+        <entry>STRING</entry>
+        <entry>
+         The optional name of the application sending the notification.
+         Can be blank.
+        </entry>
+       </row>
+       <row>
+        <entry><parameter>replaces_id</parameter></entry>
+        <entry>UINT32</entry>
+        <entry>
+         The optional notification ID that this notification replaces. The
+         server must atomically (ie with no flicker or other visual cues)
+         replace the given notification with this one. This allows clients to
+         effectively modify the notification while it's active. A value of
+         value of 0 means that this notification won't replace any
+         existing notifications.
+        </entry>
+       </row>
+       <row>
+        <entry><parameter>app_icon</parameter></entry>
+        <entry>STRING</entry>
+        <entry>
+         The optional program icon of the calling application. See <xref linkend="icons-and-images"/>.
+         Can be an empty string, indicating no icon.
+        </entry>
+       </row>
+       <row>
+        <entry><parameter>summary</parameter></entry>
+        <entry>STRING</entry>
+        <entry>The summary text briefly describing the notification.</entry>
+       </row>
+       <row>
+        <entry><parameter>body</parameter></entry>
+        <entry>STRING</entry>
+        <entry>The optional detailed body text. Can be empty.</entry>
+       </row>
+       <row>
+        <entry><parameter>actions</parameter></entry>
+        <entry>ARRAY</entry>
+        <entry>
+         Actions are sent over as a list of pairs. Each even element in
+         the list (starting at index 0) represents the identifier for the
+         action. Each odd element in the list is the localized string
+         that will be displayed to the user.
+        </entry>
+       </row>
+       <row>
+        <entry><parameter>hints</parameter></entry>
+        <entry>DICT</entry>
+        <entry>
+         Optional hints that can be passed to the server from the client
+         program. Although clients and servers should never assume each other
+         supports any specific hints, they can be used to pass along
+         information, such as the process PID or window ID, that the server
+         may be able to make use of. See <xref linkend="hints"/>. Can be
+         empty.
+        </entry>
+       </row>
+       <row>
+        <entry><parameter>expire_timeout</parameter></entry>
+        <entry>INT32</entry>
+        <entry>
+         <para>
+          The timeout time in milliseconds since the display of the notification at
+          which the notification should automatically close.
+         </para>
+         <para>
+          If -1, the notification's expiration time is dependent on the
+          notification server's settings, and may vary for the type of
+          notification.
+
+          If 0, never expire.
+         </para>
+        </entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+    <para>
+     If <parameter>replaces_id</parameter> is 0, the return value is a
+     UINT32 that represent the notification. It is unique, and will not be
+     reused unless a <constant>MAXINT</constant> number of notifications
+     have been generated. An acceptable implementation may just use an
+     incrementing counter for the ID. The returned ID is always greater than
+     zero. Servers must make sure not to return zero as an ID.
+    </para>
+    <para>
+     If <parameter>replaces_id</parameter> is not 0, the returned value
+     is the same value as <parameter>replaces_id</parameter>.
+    </para>
+   </sect3>
+
+   <sect3 id="command-close-notification">
+    <title><literal>org.freedesktop.Notifications.CloseNotification</literal></title>
+    <funcsynopsis>
+     <funcprototype>
+      <funcdef>void
+       <function>org.freedesktop.Notifications.CloseNotification</function>
+      </funcdef>
+      <paramdef>UINT32 id</paramdef>
+     </funcprototype>
+    </funcsynopsis>
+    <para>
+     Causes a notification to be forcefully closed and removed from the user's
+     view. It can be used, for example, in the event that what the
+     notification pertains to is no longer relevant, or to cancel a
+     notification with no expiration time.
+    </para>
+    <para>
+     The <literal>NotificationClosed</literal> signal is emitted by this
+     method.
+    </para>
+    <para>
+     If the notification no longer exists, an empty D-BUS Error message is
+     sent back.
+    </para>
+   </sect3>
+
+   <sect3 id="command-get-server-information">
+    <title><literal>org.freedesktop.Notifications.GetServerInformation</literal></title>
+    <funcsynopsis>
+     <funcprototype>
+      <funcdef>
+       void
+       <function>org.freedesktop.Notifications.GetServerInformation</function>
+      </funcdef>
+      <paramdef>out STRING <parameter>name</parameter></paramdef>
+      <paramdef>out STRING <parameter>vendor</parameter></paramdef>
+      <paramdef>out STRING <parameter>version</parameter></paramdef>
+      <paramdef>out STRING <parameter>spec_version</parameter></paramdef>
+     </funcprototype>
+    </funcsynopsis>
+    <para>
+     This message returns the information on the server. Specifically,
+     the server name, vendor, and version number.
+    </para>
+    <table>
+     <title>GetServerInformation Return Values</title>
+     <tgroup cols="2">
+      <thead>
+       <row>
+        <entry>Name</entry>
+        <entry>Type</entry>
+        <entry>Description</entry>
+       </row>
+      </thead>
+      <tbody valign="top">
+       <row>
+        <entry><parameter>name</parameter></entry>
+        <entry>STRING</entry>
+        <entry>The product name of the server.</entry>
+       </row>
+       <row>
+        <entry><parameter>vendor</parameter></entry>
+        <entry>STRING</entry>
+        <entry>
+         The vendor name. For example, "KDE," "GNOME,"
+         "freedesktop.org," or "Microsoft."
+        </entry>
+       </row>
+       <row>
+        <entry><parameter>version</parameter></entry>
+        <entry>STRING</entry>
+        <entry>The server's version number.</entry>
+       </row>
+       <row>
+        <entry><parameter>spec_version</parameter></entry>
+        <entry>STRING</entry>
+        <entry>The specification version the server is compliant with.</entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+   </sect3>
+  </sect2>
+
+  <sect2 id="signals">
+   <title>Signals</title>
+
+   <sect3 id="signal-notification-closed">
+    <title><literal>org.freedesktop.Notifications.NotificationClosed</literal></title>
+    <funcsynopsis>
+     <funcprototype>
+      <funcdef>
+       <function>org.freedesktop.Notifications.NotificationClosed</function>
+      </funcdef>
+      <paramdef>UINT32 <parameter>id</parameter></paramdef>
+      <paramdef>UINT32 <parameter>reason</parameter></paramdef>
+     </funcprototype>
+    </funcsynopsis>
+    <para>
+     A completed notification is one that has timed out, or has been
+     dismissed by the user.
+    </para>
+    <table>
+     <title>NotificationClosed Parameters</title>
+     <tgroup cols="2">
+      <thead>
+       <row>
+        <entry>Name</entry>
+        <entry>Type</entry>
+        <entry>Description</entry>
+       </row>
+      </thead>
+      <tbody valign="top">
+       <row>
+        <entry><parameter>id</parameter></entry>
+        <entry>UINT32</entry>
+        <entry>The ID of the notification that was closed.</entry>
+       </row>
+       <row>
+        <entry><parameter>reason</parameter></entry>
+        <entry>UINT32</entry>
+        <entry>
+         <para>The reason the notification was closed.</para>
+         <para>1 - The notification expired.</para>
+         <para>2 - The notification was dismissed by the user.</para>
+         <para>3 - The notification was closed by a call to
+               <literal>CloseNotification</literal>.</para>
+         <para>4 - Undefined/reserved reasons.</para>
+        </entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+    <para>
+     The ID specified in the signal is invalidated
+     <emphasis>before</emphasis> the signal is sent and may not be used
+     in any further communications with the server.
+    </para>
+   </sect3>
+
+   <sect3 id="signal-action-invoked">
+    <title><literal>org.freedesktop.Notifications.ActionInvoked</literal></title>
+    <funcsynopsis>
+     <funcprototype>
+      <funcdef>
+       <function>org.freedesktop.Notifications.ActionInvoked</function>
+      </funcdef>
+      <paramdef>UINT32 <parameter>id</parameter></paramdef>
+      <paramdef>STRING <parameter>action_key</parameter></paramdef>
+     </funcprototype>
+    </funcsynopsis>
+    <para>
+     This signal is emitted when one of the following occurs:
+    </para>
+    <itemizedlist>
+     <listitem>
+      <para>
+       The user performs some global "invoking" action upon a notification.
+       For instance, clicking somewhere on the notification itself.
+      </para>
+     </listitem>
+     <listitem>
+      <para>
+       The user invokes a specific action as specified in the original
+       Notify request. For example, clicking on an action button.
+      </para>
+     </listitem>
+    </itemizedlist>
+    <table>
+     <title>ActionInvoked Parameters</title>
+     <tgroup cols="2">
+      <thead>
+       <row>
+        <entry>Name</entry>
+        <entry>Type</entry>
+        <entry>Description</entry>
+       </row>
+      </thead>
+      <tbody valign="top">
+       <row>
+        <entry><parameter>id</parameter></entry>
+        <entry>UINT32</entry>
+        <entry>
+         The ID of the notification emitting the ActionInvoked signal.
+        </entry>
+       </row>
+       <row>
+        <entry><parameter>action_key</parameter></entry>
+        <entry>STRING</entry>
+        <entry>
+         The key of the action invoked. These match the keys sent over
+         in the list of actions.
+        </entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+    <note>
+     <para>
+      Clients should not assume the server will generate this signal. Some
+      servers may not support user interaction at all, or may not support
+      the concept of being able to "invoke" a notification.
+     </para>
+    </note>
+   </sect3>
+  </sect2>
+ </sect1>
+</article>
diff --git a/src/lib/notification/notification.c b/src/lib/notification/notification.c
new file mode 100644 (file)
index 0000000..a56d2c5
--- /dev/null
@@ -0,0 +1,557 @@
+#include "E_Notify.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include "e_notify_private.h"
+
+/* private functions */
+static Eina_List             *e_notification_action_list_new(void);
+static E_Notification_Action *e_notification_action_new(const char *id,
+                                                        const char *name);
+
+int _e_dbus_notify_log_dom = -1;
+
+void
+loginit(void)
+{
+   if (_e_dbus_notify_log_dom == -1)
+     _e_dbus_notify_log_dom = eina_log_domain_register("e_dbus_notify", E_DBUS_COLOR_DEFAULT);
+}
+
+/* (con|de)structor */
+
+EAPI E_Notification *
+e_notification_full_new(const char *app_name, unsigned int replaces_id, const char *app_icon, const char *summary, const char *body, int expire_timeout)
+{
+   E_Notification *n;
+
+   loginit();
+   n = e_notification_new();
+   if (!n) return NULL;
+
+   n->app_name = eina_stringshare_add(app_name);
+   n->replaces_id = replaces_id;
+   n->app_icon = eina_stringshare_add(app_icon);
+   n->summary = eina_stringshare_add(summary);
+   n->body = eina_stringshare_add(body);
+   n->expire_timeout = expire_timeout;
+   n->hints.x = n->hints.y = -1;
+
+   return n;
+}
+
+EAPI E_Notification *
+e_notification_new(void)
+{
+   E_Notification *n;
+   
+   loginit();
+   n = calloc(1, sizeof(E_Notification));
+   if (!n) return NULL;
+   n->refcount = 1;
+
+   return n;
+}
+
+EAPI void
+e_notification_ref(E_Notification *n)
+{
+   loginit();
+   n->refcount++;
+}
+
+EAPI void
+e_notification_unref(E_Notification *n)
+{
+   loginit();
+   if (--n->refcount == 0) e_notification_free(n);
+}
+
+EAPI void
+e_notification_free(E_Notification *n)
+{
+   loginit();
+   if (!n) return;
+
+   eina_stringshare_del(n->app_name);
+   eina_stringshare_del(n->app_icon);
+   eina_stringshare_del(n->summary);
+   eina_stringshare_del(n->body);
+
+   eina_list_free(n->actions);
+
+   eina_stringshare_del(n->hints.category);
+   eina_stringshare_del(n->hints.desktop);
+   eina_stringshare_del(n->hints.sound_file);
+   if (n->hints.image_data) e_notification_image_free(n->hints.image_data);
+   if (n->hints.icon_data) e_notification_image_free(n->hints.icon_data);
+   free(n);
+}
+
+/* mutators */
+EAPI void
+e_notification_id_set(E_Notification *note, unsigned int id)
+{
+   loginit();
+   note->id = id;
+}
+
+EAPI void
+e_notification_app_name_set(E_Notification *note, const char *app_name)
+{
+   loginit();
+   eina_stringshare_replace(&note->app_name, app_name);
+}
+
+EAPI void
+e_notification_app_icon_set(E_Notification *note, const char *app_icon)
+{
+   loginit();
+   eina_stringshare_replace(&note->app_icon, app_icon);
+}
+
+EAPI void
+e_notification_summary_set(E_Notification *note, const char *summary)
+{
+   loginit();
+   eina_stringshare_replace(&note->summary, summary);
+}
+
+EAPI void
+e_notification_body_set(E_Notification *note, const char *body)
+{
+   loginit();
+   eina_stringshare_replace(&note->body, body);
+}
+
+EAPI void
+e_notification_action_add(E_Notification *n, const char *action_id, const char *action_name)
+{
+   E_Notification_Action *a;
+
+   loginit();
+   if (!n->actions)
+     n->actions = e_notification_action_list_new();
+
+   a = e_notification_action_new(action_id, action_name);
+   n->actions = eina_list_append(n->actions, a);
+}
+
+EAPI void
+e_notification_replaces_id_set(E_Notification *note, int replaces_id)
+{
+   loginit();
+   note->replaces_id = replaces_id;
+}
+
+EAPI void
+e_notification_timeout_set(E_Notification *note, int timeout)
+{
+   loginit();
+   note->expire_timeout = timeout;
+}
+
+EAPI void
+e_notification_closed_set(E_Notification *note, unsigned char closed)
+{
+   loginit();
+   note->closed = closed;
+}
+
+/* accessors */
+EAPI unsigned int
+e_notification_id_get(E_Notification *note)
+{
+   loginit();
+   return note->id;
+}
+
+EAPI const char *
+e_notification_app_name_get(E_Notification *note)
+{
+   loginit();
+   return note->app_name;
+}
+
+EAPI const char *
+e_notification_app_icon_get(E_Notification *note)
+{
+   loginit();
+   return note->app_icon;
+}
+
+EAPI const char *
+e_notification_summary_get(E_Notification *note)
+{
+   loginit();
+   return note->summary;
+}
+
+EAPI const char *
+e_notification_body_get(E_Notification *note)
+{
+   loginit();
+   return note->body;
+}
+
+EAPI Eina_List *
+e_notification_actions_get(E_Notification *note)
+{
+   loginit();
+   return note->actions;
+}
+
+EAPI int
+e_notification_replaces_id_get(E_Notification *note)
+{
+   loginit();
+   return note->replaces_id;
+}
+
+EAPI int
+e_notification_timeout_get(E_Notification *note)
+{
+   loginit();
+   return note->expire_timeout;
+}
+
+EAPI unsigned char
+e_notification_closed_get(E_Notification *note)
+{
+   loginit();
+   return note->closed;
+}
+
+/***** actions *****/
+
+static Eina_List *
+e_notification_action_list_new(void)
+{
+   Eina_List *alist;
+
+   loginit();
+   alist = NULL;
+   return alist;
+}
+
+static E_Notification_Action *
+e_notification_action_new(const char *id, const char *name)
+{
+   E_Notification_Action *act;
+   
+   loginit();
+   act = malloc(sizeof(E_Notification_Action));
+   act->id = eina_stringshare_add(id);
+   act->name = eina_stringshare_add(name);
+   return act;
+}
+
+EAPI const char *
+e_notification_action_id_get(E_Notification_Action *a)
+{
+   loginit();
+   EINA_SAFETY_ON_NULL_RETURN_VAL(a, NULL);
+   return a->id;
+}
+
+EAPI const char *
+e_notification_action_name_get(E_Notification_Action *a)
+{
+   loginit();
+   EINA_SAFETY_ON_NULL_RETURN_VAL(a, NULL);
+   return a->name;
+}
+
+/********* hints *******/
+EAPI void
+e_notification_hint_transient_set(E_Notification *n, Eina_Bool transient)
+{
+   loginit();
+   if (transient)
+     n->hint_flags |= E_NOTIFICATION_HINT_TRANSIENT;
+   else
+     n->hint_flags ^= E_NOTIFICATION_HINT_TRANSIENT;
+}
+
+EAPI void
+e_notification_hint_resident_set(E_Notification *n, Eina_Bool resident)
+{
+   loginit();
+   if (resident)
+     n->hint_flags |= E_NOTIFICATION_HINT_RESIDENT;
+   else
+     n->hint_flags ^= E_NOTIFICATION_HINT_RESIDENT;
+}
+
+EAPI void
+e_notification_hint_action_icons_set(E_Notification *n, Eina_Bool action_icons)
+{
+   loginit();
+   if (action_icons)
+     n->hint_flags |= E_NOTIFICATION_HINT_ACTION_ICONS;
+   else
+     n->hint_flags ^= E_NOTIFICATION_HINT_ACTION_ICONS;
+}
+
+EAPI void
+e_notification_hint_urgency_set(E_Notification *n, char urgency)
+{
+   loginit();
+   n->hints.urgency = urgency;
+   n->hint_flags |= E_NOTIFICATION_HINT_URGENCY;
+}
+
+EAPI void
+e_notification_hint_image_path_set(E_Notification *n, const char *path)
+{
+   loginit();
+   eina_stringshare_replace(&n->hints.image_path, path);
+}
+
+EAPI void
+e_notification_hint_category_set(E_Notification *n, const char *category)
+{
+   loginit();
+   eina_stringshare_replace(&n->hints.category, category);
+   n->hint_flags |= E_NOTIFICATION_HINT_CATEGORY;
+}
+
+EAPI void
+e_notification_hint_desktop_set(E_Notification *n, const char *desktop)
+{
+   loginit();
+   eina_stringshare_replace(&n->hints.desktop, desktop);
+   n->hint_flags |= E_NOTIFICATION_HINT_DESKTOP;
+}
+
+EAPI void
+e_notification_hint_sound_file_set(E_Notification *n, const char *sound_file)
+{
+   loginit();
+   eina_stringshare_replace(&n->hints.sound_file, sound_file);
+   n->hint_flags |= E_NOTIFICATION_HINT_SOUND_FILE;
+}
+
+EAPI void
+e_notification_hint_suppress_sound_set(E_Notification *n, char suppress_sound)
+{
+   loginit();
+   n->hints.suppress_sound = suppress_sound;
+   n->hint_flags |= E_NOTIFICATION_HINT_SUPPRESS_SOUND;
+}
+
+EAPI void
+e_notification_hint_xy_set(E_Notification *n, int x, int y)
+{
+   loginit();
+   n->hints.x = x;
+   n->hints.y = y;
+   n->hint_flags |= E_NOTIFICATION_HINT_XY;
+}
+
+EAPI void
+e_notification_hint_image_data_set(E_Notification *n, E_Notification_Image *image)
+{
+   loginit();
+   n->hints.image_data = image;
+}
+
+EAPI char
+e_notification_hint_urgency_get(E_Notification *n)
+{
+   loginit();
+   return n->hint_flags & E_NOTIFICATION_HINT_URGENCY ? n->hints.urgency : 1;
+}
+
+EAPI const char *
+e_notification_hint_category_get(E_Notification *n)
+{
+   loginit();
+   return n->hints.category;
+}
+
+EAPI const char *
+e_notification_hint_desktop_get(E_Notification *n)
+{
+   loginit();
+   return n->hints.desktop;
+}
+
+EAPI const char *
+e_notification_hint_image_path_get(E_Notification *n)
+{
+   loginit();
+   return n->hints.image_path;
+}
+
+EAPI const char *
+e_notification_hint_sound_file_get(E_Notification *n)
+{
+   loginit();
+   return n->hints.sound_file;
+}
+
+EAPI char
+e_notification_hint_suppress_sound_get(E_Notification *n)
+{
+   loginit();
+   return n->hints.suppress_sound;
+}
+
+EAPI int
+e_notification_hint_xy_get(E_Notification *n, int *x, int *y)
+{
+   loginit();
+   if (x) *x = n->hints.x;
+   if (y) *y = n->hints.y;
+
+   return n->hint_flags & E_NOTIFICATION_HINT_XY ? 1 : 0;
+}
+
+EAPI E_Notification_Image *
+e_notification_hint_image_data_get(E_Notification *n)
+{
+   loginit();
+   return n->hints.image_data;
+}
+
+EAPI E_Notification_Image *
+e_notification_hint_icon_data_get(E_Notification *n)
+{
+   loginit();
+   return n->hints.icon_data;
+}
+
+EAPI E_Notification_Image *
+e_notification_image_new(void)
+{
+   E_Notification_Image *img;
+
+   loginit();
+   img = calloc(1, sizeof(E_Notification_Image));
+   img->bits_per_sample = 8;
+   return img;
+}
+
+EAPI Eina_Bool
+e_notification_image_init(E_Notification_Image *img, Evas_Object *obj)
+{
+   int x, y, w = 0, h = 0;
+   unsigned char *d, *imgdata;
+   int rowstride;
+   int *s;
+   
+   loginit();
+   EINA_SAFETY_ON_NULL_RETURN_VAL(img, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
+
+   evas_object_image_size_get(obj, &w, &h);
+   if ((w <= 0) || (h <= 0)) return EINA_FALSE;
+   imgdata = evas_object_image_data_get(obj, EINA_FALSE);
+   if (!imgdata) return EINA_FALSE;
+   
+   img->data = malloc(4 * w * h);
+   if (!img->data)
+     {
+        evas_object_image_data_set(obj, imgdata);
+        return EINA_FALSE;
+     }
+   img->channels = 4;
+   img->rowstride = 4 * w;
+   img->width = w;
+   img->height = h;
+   img->bits_per_sample = 8;
+   img->has_alpha = EINA_TRUE;
+   
+   rowstride = evas_object_image_stride_get(obj);
+   for (y = 0; y < img->height; y++)
+     {
+        s = (int *)(imgdata + (y * rowstride));
+        d = img->data + (y * img->rowstride);
+        
+        for (x = 0; x < img->width; x++, s++)
+          {
+             *d++ = (*s >> 16) & 0xff;
+             *d++ = (*s >> 8) & 0xff;
+             *d++ = (*s) & 0xff;
+             *d++ = (*s >> 24) & 0xff;
+          }
+     }
+   
+   evas_object_image_data_set(obj, imgdata);
+   return EINA_TRUE;
+}
+
+EAPI void
+e_notification_image_free(E_Notification_Image *img)
+{
+   loginit();
+   if (!img) return;
+   free(img->data);
+   free(img);
+}
+
+static Eina_Bool
+_e_notification_image_evas_object_fill(E_Notification_Image *img, Evas_Object *obj)
+{
+   unsigned char *imgdata;
+   
+   EINA_SAFETY_ON_NULL_RETURN_VAL(img, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
+
+   evas_object_image_colorspace_set(obj, EVAS_COLORSPACE_ARGB8888);
+   evas_object_image_alpha_set(obj, img->has_alpha);
+   evas_object_image_size_set(obj, img->width, img->height);
+   
+   imgdata = evas_object_image_data_get(obj, EINA_TRUE);
+   if (!imgdata) return EINA_FALSE;
+   
+   if (img->bits_per_sample == 8)
+     {
+        /* Although not specified.
+         * The data are very likely to come from a GdkPixbuf
+         * which align each row on a 4-bytes boundary when using RGB.
+         * And is RGBA otherwise. */
+        int x, y, *d;
+        unsigned char *s;
+        int rowstride;
+        
+        rowstride = evas_object_image_stride_get(obj);
+        for (y = 0; y < img->height; y++)
+          {
+             s = img->data + (y * img->rowstride);
+             d = (int *)(imgdata + (y * rowstride));
+
+             for (x = 0; x < img->width; x++, s += img->channels, d++)
+               {
+                  if (img->has_alpha)
+                    *d = (s[3] << 24) | (s[0] << 16) | (s[1] << 8) | (s[2]);
+                  else
+                    *d = (0xff << 24) | (s[0] << 16) | (s[1] << 8) | (s[2]);
+               }
+          }
+     }
+   evas_object_image_data_update_add(obj, 0, 0, img->width, img->height);
+   evas_object_image_data_set(obj, imgdata);
+   
+   return EINA_TRUE;
+}
+
+EAPI Evas_Object *
+e_notification_image_evas_object_add(Evas *evas, E_Notification_Image *img)
+{
+   Evas_Object *o = NULL;
+
+   loginit();
+   if ((!evas) || (!img)) return NULL;
+   o = evas_object_image_filled_add(evas);
+   evas_object_resize(o, img->width, img->height);
+   if (!_e_notification_image_evas_object_fill(img, o))
+     {
+        evas_object_del(o);
+        return NULL;
+     }
+   return o;
+}
+
diff --git a/src/lib/ofono/E_Ofono.h b/src/lib/ofono/E_Ofono.h
new file mode 100644 (file)
index 0000000..d96f74b
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef E_OFONO_H
+#define E_OFONO_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+#include <E_DBus.h>
+
+/**
+ * @defgroup EOfono_Group EOfono
+ *
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Ecore Events */
+extern int E_OFONO_EVENT_MANAGER_IN;
+extern int E_OFONO_EVENT_MANAGER_OUT;
+extern int E_OFONO_EVENT_ELEMENT_ADD;
+extern int E_OFONO_EVENT_ELEMENT_DEL;
+extern int E_OFONO_EVENT_ELEMENT_UPDATED;
+
+typedef struct _E_Ofono_Element   E_Ofono_Element;
+
+struct _E_Ofono_Element
+{
+   const char            *path;
+   const char            *interface;
+   E_DBus_Signal_Handler *signal_handler;
+   Eina_Inlist           *props;
+
+   /* private */
+   struct
+   {
+      Eina_Inlist *properties_get;
+      Eina_Inlist *property_set;
+      Eina_Inlist *send_sms;
+   } _pending;
+   struct
+   {
+      Ecore_Idler *changed;
+   } _idler;
+   Eina_Inlist *_listeners;
+   int          _references;
+};
+
+/* General Public API */
+EAPI unsigned int         e_ofono_system_init(E_DBus_Connection *edbus_conn) EINA_ARG_NONNULL(1);
+EAPI unsigned int         e_ofono_system_shutdown(void);
+
+/* Manager Methods */
+EAPI E_Ofono_Element *    e_ofono_manager_get(void) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_manager_modems_get(Eina_Array **array);
+
+/* Modem Methods */
+EAPI Eina_Bool            e_ofono_modem_powered_get(const E_Ofono_Element *element, Eina_Bool *powered) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_modem_powered_set(E_Ofono_Element *element, Eina_Bool powered, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_modem_name_get(const E_Ofono_Element *element, const char **name) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+/* NetworkRegistration Methods */
+EAPI Eina_Bool            e_ofono_netreg_mode_get(const E_Ofono_Element *element, const char **mode) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_netreg_status_get(const E_Ofono_Element *element, const char **status) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_netreg_operator_get(const E_Ofono_Element *element, const char **op) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_netreg_strength_get(const E_Ofono_Element *element, uint8_t *strength) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+/* SMS Methods */
+EAPI Eina_Bool            e_ofono_sms_sca_get(const E_Ofono_Element *element, const char **sca) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_sms_sca_set(E_Ofono_Element *element, const char *sca, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_sms_send_message(E_Ofono_Element *element, const char *number, const char *message, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+
+/* Low-Level API:
+ *
+ * Should just be used to work around problems until proper solution
+ * is made into e_ofono.
+ */
+EAPI Eina_Bool            e_ofono_manager_sync_elements(void);
+
+EAPI Eina_Bool            e_ofono_elements_get_all(unsigned int *count, E_Ofono_Element ***p_elements) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_elements_get_all_type(const char *type, unsigned int *count, E_Ofono_Element ***p_elements) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI E_Ofono_Element *    e_ofono_element_get(const char *path, const char *interface) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+EAPI void                 e_ofono_element_listener_add(E_Ofono_Element *element, void (*cb)(void *data, const E_Ofono_Element *element), const void *data, void (*free_data)(void *data)) EINA_ARG_NONNULL(1, 2);
+EAPI void                 e_ofono_element_listener_del(E_Ofono_Element *element, void (*cb)(void *data, const E_Ofono_Element *element), const void *data) EINA_ARG_NONNULL(1, 2);
+
+EAPI int                  e_ofono_element_ref(E_Ofono_Element *element) EINA_ARG_NONNULL(1);
+EAPI int                  e_ofono_element_unref(E_Ofono_Element *element) EINA_ARG_NONNULL(1);
+
+EAPI void                 e_ofono_element_print(FILE *fp, const E_Ofono_Element *element) EINA_ARG_NONNULL(1, 2);
+
+EAPI Eina_Bool            e_ofono_element_properties_sync(E_Ofono_Element *element) EINA_ARG_NONNULL(1);
+EAPI Eina_Bool            e_ofono_element_properties_sync_full(E_Ofono_Element *element, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1);
+
+EAPI Eina_Bool            e_ofono_element_property_set(E_Ofono_Element *element, const char *prop, int type, const void *value) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_element_property_set_full(E_Ofono_Element *element, const char *prop, int type, const void *value, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_element_property_dict_set_full(E_Ofono_Element *element, const char *prop, const char *key, int type, const void *value, E_DBus_Method_Return_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+
+EAPI void                 e_ofono_element_properties_list(const E_Ofono_Element *element, Eina_Bool (*cb)(void *data, const E_Ofono_Element *element, const char *name, int type, const void *value), const void *data) EINA_ARG_NONNULL(1, 2);
+
+EAPI Eina_Bool            e_ofono_element_property_type_get_stringshared(const E_Ofono_Element *element, const char *name, int *type) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_element_property_type_get(const E_Ofono_Element *element, const char *name, int *type) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_element_property_dict_get_stringshared(const E_Ofono_Element *element, const char *dict_name, const char *key_name, int *type, void *value) EINA_ARG_NONNULL(1, 2, 4) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_element_property_get_stringshared(const E_Ofono_Element *element, const char *name, int *type, void *value) EINA_ARG_NONNULL(1, 2, 4) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_element_property_get(const E_Ofono_Element *element, const char *name, int *type, void *value) EINA_ARG_NONNULL(1, 2, 4) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool            e_ofono_element_is_manager(const E_Ofono_Element *element) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_element_is_modem(const E_Ofono_Element *element) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool            e_ofono_element_is_netreg(const E_Ofono_Element *element) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+
+#endif /* E_OFONO_H */
diff --git a/src/lib/ofono/Makefile.am b/src/lib/ofono/Makefile.am
new file mode 100644 (file)
index 0000000..f90cb8d
--- /dev/null
@@ -0,0 +1,24 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I $(top_srcdir)/src/lib/dbus \
+@EDBUS_CFLAGS@
+
+lib_LTLIBRARIES = libeofono.la
+includes_HEADERS = E_Ofono.h
+includesdir = $(includedir)/e_dbus-@VMAJ@
+
+libeofono_la_SOURCES = \
+e_ofono.c \
+e_ofono_element.c \
+e_ofono_manager.c \
+e_ofono_modem.c \
+e_ofono_network_reg.c \
+e_ofono_sms.c
+
+libeofono_la_LIBADD = \
+@EDBUS_LIBS@ $(top_builddir)/src/lib/dbus/libedbus.la
+
+libeofono_la_LDFLAGS = -version-info @version_info@ @release_info@
+
+EXTRA_DIST = e_ofono_private.h
diff --git a/src/lib/ofono/e_ofono.c b/src/lib/ofono/e_ofono.c
new file mode 100644 (file)
index 0000000..db0566f
--- /dev/null
@@ -0,0 +1,339 @@
+#include "e_ofono_private.h"
+#include <stdlib.h>
+#include <string.h>
+
+static E_DBus_Signal_Handler *cb_name_owner_changed = NULL;
+static DBusPendingCall *pending_get_name_owner = NULL;
+static unsigned int init_count = 0;
+static char *unique_name = NULL;
+
+static const char bus_name[] = "org.ofono";
+
+E_DBus_Connection *e_ofono_conn = NULL;
+
+EAPI int E_OFONO_EVENT_MANAGER_IN = 0;
+EAPI int E_OFONO_EVENT_MANAGER_OUT = 0;
+EAPI int E_OFONO_EVENT_ELEMENT_ADD = 0;
+EAPI int E_OFONO_EVENT_ELEMENT_DEL = 0;
+EAPI int E_OFONO_EVENT_ELEMENT_UPDATED = 0;
+
+const char *e_ofono_iface_manager = NULL;
+const char *e_ofono_prop_modems = NULL;
+const char *e_ofono_iface_modem = NULL;
+const char *e_ofono_prop_name = NULL;
+const char *e_ofono_prop_powered = NULL;
+const char *e_ofono_prop_interfaces = NULL;
+const char *e_ofono_iface_netreg = NULL;
+const char *e_ofono_prop_mode = NULL;
+const char *e_ofono_prop_status = NULL;
+const char *e_ofono_prop_operator = NULL;
+const char *e_ofono_prop_strength = NULL;
+const char *e_ofono_iface_sms = NULL;
+const char *e_ofono_prop_sca = NULL;
+const char *e_ofono_method_send_sms = NULL;
+
+int _e_dbus_ofono_log_dom = -1;
+
+const char *
+e_ofono_system_bus_name_get(void)
+{
+   return unique_name ? unique_name : bus_name;
+}
+
+/***********************************************************************
+* Manager
+***********************************************************************/
+
+/*
+ * FIXME: Do we really need to call Manager.GetProperties()?
+ */
+
+/**
+ * Synchronize elements with server.
+ *
+ * This will call Manager.GetProperties() on server, retrieve properties
+ * and some element paths and then request their properties.
+ *
+ * This call will add events E_OFONO_EVENT_ELEMENT_ADD and
+ * E_OFONO_EVENT_ELEMENT_UPDATED to the main loop.
+ *
+ * This will not remove stale elements.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_manager_sync_elements(void)
+{
+   E_Ofono_Element *manager;
+
+   if (!unique_name)
+      return FALSE;
+
+   manager = e_ofono_element_register(manager_path, e_ofono_iface_manager);
+   if (manager)
+      e_ofono_element_properties_sync(manager);
+   else
+      return FALSE;
+
+   DBG("sync_manager: %s (%s)", unique_name, bus_name);
+
+   return TRUE;
+}
+
+static void
+_e_ofono_system_name_owner_exit(void)
+{
+   e_ofono_manager_clear_elements();
+   ecore_event_add(E_OFONO_EVENT_MANAGER_OUT, NULL, NULL, NULL);
+
+   free(unique_name);
+   unique_name = NULL;
+}
+
+static void
+_e_ofono_system_name_owner_enter(const char *uid)
+{
+   DBG("enter ofono at %s (old was %s)", uid, unique_name);
+   if (unique_name && strcmp(unique_name, uid) == 0)
+     {
+        DBG("same unique_name for ofono, ignore.");
+        return;
+     }
+
+   if (unique_name)
+      _e_ofono_system_name_owner_exit();
+
+   unique_name = strdup(uid);
+
+   ecore_event_add(E_OFONO_EVENT_MANAGER_IN, NULL, NULL, NULL);
+   e_ofono_manager_sync_elements();
+}
+
+static void
+_e_ofono_system_name_owner_changed(void *data __UNUSED__, DBusMessage *msg)
+{
+   DBusError err;
+   const char *name, *from, *to;
+
+   dbus_error_init(&err);
+   if (!dbus_message_get_args(msg, &err,
+                              DBUS_TYPE_STRING, &name,
+                              DBUS_TYPE_STRING, &from,
+                              DBUS_TYPE_STRING, &to,
+                              DBUS_TYPE_INVALID))
+     {
+        ERR("could not get NameOwnerChanged arguments: %s: %s",
+            err.name, err.message);
+        dbus_error_free(&err);
+        return;
+     }
+
+   if (strcmp(name, bus_name) != 0)
+      return;
+
+   DBG("NameOwnerChanged from=[%s] to=[%s]", from, to);
+
+   if (from[0] == '\0' && to[0] != '\0')
+     {
+        _e_ofono_system_name_owner_enter(to);
+     }
+   else if (from[0] != '\0' && to[0] == '\0')
+     {
+        DBG("exit ofono at %s", from);
+        if (strcmp(unique_name, from) != 0)
+           DBG("%s was not the known name %s, ignored.", from, unique_name);
+        else
+           _e_ofono_system_name_owner_exit();
+     }
+   else
+     {
+        DBG("unknow change from %s to %s", from, to);
+     }
+}
+
+static void
+_e_ofono_get_name_owner(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
+{
+   DBusMessageIter itr;
+   int t;
+   const char *uid;
+
+   pending_get_name_owner = NULL;
+
+   if (!_dbus_callback_check_and_init(msg, &itr, err))
+      return;
+
+   t = dbus_message_iter_get_arg_type(&itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
+      return;
+
+   dbus_message_iter_get_basic(&itr, &uid);
+   if (!uid)
+     {
+        ERR("no name owner!");
+        return;
+     }
+
+   _e_ofono_system_name_owner_enter(uid);
+   return;
+}
+
+/**
+ * Initialize E oFono (E_Ofono) system.
+ *
+ * This will connect and watch org.ofono.Manager and Element
+ * events and translate to Ecore main loop events, also provide a
+ * proxy for method invocation on server.
+ *
+ * Interesting events are:
+ *   - E_OFONO_EVENT_MANAGER_IN: issued when ofono is avaiable.
+ *   - E_OFONO_EVENT_MANAGER_OUT: issued when ofono connection is lost.
+ *   - E_OFONO_EVENT_ELEMENT_ADD: element was added.
+ *   - E_OFONO_EVENT_ELEMENT_DEL: element was deleted.
+ *   - E_OFONO_EVENT_ELEMENT_UPDATED: element was updated (properties
+ *     or state changed).
+ *
+ * Manager IN/OUT events do not provide any event information, just
+ * tells you that system is usable or not. After manager is out, all
+ * elements will be removed, so after this event do not use the system anymore.
+ *
+ * Element events will give you an element object. After DEL event callback
+ * returns, that element will not be valid anymore.
+ */
+unsigned int
+e_ofono_system_init(E_DBus_Connection *edbus_conn)
+{
+   init_count++;
+
+   if (init_count > 1)
+      return init_count;
+
+   _e_dbus_ofono_log_dom = eina_log_domain_register
+         ("e_dbus_ofono", EINA_LOG_DEFAULT_COLOR);
+
+   if(_e_dbus_ofono_log_dom < 0)
+     {
+        EINA_LOG_ERR
+           ("impossible to create a log domain for edbus_ofono module");
+        return -1;
+     }
+
+   if (E_OFONO_EVENT_MANAGER_IN == 0)
+      E_OFONO_EVENT_MANAGER_IN = ecore_event_type_new();
+
+   if (E_OFONO_EVENT_MANAGER_OUT == 0)
+      E_OFONO_EVENT_MANAGER_OUT = ecore_event_type_new();
+
+   if (E_OFONO_EVENT_ELEMENT_ADD == 0)
+      E_OFONO_EVENT_ELEMENT_ADD = ecore_event_type_new();
+
+   if (E_OFONO_EVENT_ELEMENT_DEL == 0)
+      E_OFONO_EVENT_ELEMENT_DEL = ecore_event_type_new();
+
+   if (E_OFONO_EVENT_ELEMENT_UPDATED == 0)
+      E_OFONO_EVENT_ELEMENT_UPDATED = ecore_event_type_new();
+
+   if (!e_ofono_iface_manager)
+      e_ofono_iface_manager = eina_stringshare_add("org.ofono.Manager");
+
+   if (!e_ofono_prop_modems)
+      e_ofono_prop_modems = eina_stringshare_add("Modems");
+
+   if (!e_ofono_iface_modem)
+      e_ofono_iface_modem = eina_stringshare_add("org.ofono.Modem");
+
+   if (!e_ofono_prop_name)
+      e_ofono_prop_name = eina_stringshare_add("Name");
+
+   if (!e_ofono_prop_powered)
+      e_ofono_prop_powered = eina_stringshare_add("Powered");
+
+   if (!e_ofono_prop_interfaces)
+      e_ofono_prop_interfaces = eina_stringshare_add("Interfaces");
+
+   if (!e_ofono_iface_netreg)
+      e_ofono_iface_netreg = eina_stringshare_add("org.ofono.NetworkRegistration");
+
+   if (!e_ofono_prop_mode)
+      e_ofono_prop_mode = eina_stringshare_add("Mode");
+
+   if (!e_ofono_prop_status)
+      e_ofono_prop_status = eina_stringshare_add("Status");
+
+   if (!e_ofono_prop_operator)
+      e_ofono_prop_operator = eina_stringshare_add("Operator");
+
+   if (!e_ofono_prop_strength)
+      e_ofono_prop_strength = eina_stringshare_add("Strength");
+
+   if (!e_ofono_iface_sms)
+      e_ofono_iface_sms = eina_stringshare_add("org.ofono.SmsManager");
+
+   if (!e_ofono_prop_sca)
+      e_ofono_prop_sca = eina_stringshare_add("ServiceCenterAddress");
+
+   if (!e_ofono_method_send_sms)
+      e_ofono_method_send_sms = eina_stringshare_add("SendMessage");
+
+   e_ofono_conn = edbus_conn;
+   cb_name_owner_changed = e_dbus_signal_handler_add
+         (e_ofono_conn, E_DBUS_FDO_BUS, E_DBUS_FDO_PATH, E_DBUS_FDO_INTERFACE, "NameOwnerChanged",
+         _e_ofono_system_name_owner_changed, NULL);
+
+   if (pending_get_name_owner)
+      dbus_pending_call_cancel(pending_get_name_owner);
+
+   pending_get_name_owner = e_dbus_get_name_owner
+         (e_ofono_conn, bus_name, _e_ofono_get_name_owner, NULL);
+
+   e_ofono_elements_init();
+
+   return init_count;
+}
+
+static inline void
+_stringshare_del(const char **str)
+{
+   if (!*str)
+      return;
+
+   eina_stringshare_del(*str);
+   *str = NULL;
+}
+
+/**
+ * Shutdown ofono system.
+ *
+ * When count drops to 0 resources will be released and no calls should be
+ * made anymore.
+ */
+unsigned int
+e_ofono_system_shutdown(void)
+{
+   if (init_count == 0)
+     {
+        ERR("ofono system already shut down.");
+        return 0;
+     }
+
+   init_count--;
+   if (init_count > 0)
+      return init_count;
+
+   _stringshare_del(&e_ofono_iface_manager);
+   _stringshare_del(&e_ofono_prop_modems);
+   _stringshare_del(&e_ofono_iface_modem);
+   _stringshare_del(&e_ofono_prop_name);
+   _stringshare_del(&e_ofono_prop_powered);
+   _stringshare_del(&e_ofono_prop_interfaces);
+   _stringshare_del(&e_ofono_iface_netreg);
+   _stringshare_del(&e_ofono_prop_mode);
+   _stringshare_del(&e_ofono_prop_status);
+   _stringshare_del(&e_ofono_prop_operator);
+   _stringshare_del(&e_ofono_prop_strength);
+   _stringshare_del(&e_ofono_iface_sms);
+   _stringshare_del(&e_ofono_prop_sca);
+   _stringshare_del(&e_ofono_method_send_sms);
+   return 0;
+}
+
diff --git a/src/lib/ofono/e_ofono_element.c b/src/lib/ofono/e_ofono_element.c
new file mode 100644 (file)
index 0000000..716c071
--- /dev/null
@@ -0,0 +1,2482 @@
+#include "e_ofono_private.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/*
+ * Maximum size for elements hash key.
+ *
+ * The elements hash key is contructed by concatenating the object path and the
+ * interface for the element (with a colon separating the two strings). D-Bus
+ * interfaces have a maximum size of 255 but object paths have unlimited size.
+ * We're assuming a maximum key size of 4k here, but this might need to be
+ * increased if oFono object paths grows bigger than that.
+ */
+#define MAX_KEY_SIZE 4096
+static Eina_Hash *elements = NULL;
+
+typedef struct _E_Ofono_Element_Pending      E_Ofono_Element_Pending;
+typedef struct _E_Ofono_Element_Call_Data    E_Ofono_Element_Call_Data;
+typedef struct _E_Ofono_Element_Property     E_Ofono_Element_Property;
+typedef struct _E_Ofono_Element_Listener     E_Ofono_Element_Listener;
+typedef struct _E_Ofono_Element_Dict_Entry   E_Ofono_Element_Dict_Entry;
+
+struct _E_Ofono_Element_Pending
+{
+                           EINA_INLIST;
+   DBusPendingCall        *pending;
+   void                   *data;
+   E_DBus_Method_Return_Cb user_cb;
+   void                   *user_data;
+};
+
+struct _E_Ofono_Element_Call_Data
+{
+   E_Ofono_Element         *element;
+   E_DBus_Method_Return_Cb  cb;
+   E_Ofono_Element_Pending *pending;
+   Eina_Inlist            **p_list;
+};
+
+struct _E_Ofono_Element_Property
+{
+               EINA_INLIST;
+   const char *name;
+   int         type;
+   union {
+      Eina_Bool      boolean;
+      const char    *str;
+      unsigned short u16;
+      unsigned int   u32;
+      unsigned char  byte;
+      const char    *path;
+      void          *variant;
+      E_Ofono_Array *array;
+   } value;
+};
+
+struct _E_Ofono_Element_Dict_Entry
+{
+   const char *name;
+   int         type;
+   union {
+      Eina_Bool      boolean;
+      const char    *str;
+      unsigned short u16;
+      unsigned int   u32;
+      unsigned char  byte;
+      const char    *path;
+   } value;
+};
+
+struct _E_Ofono_Element_Listener
+{
+         EINA_INLIST;
+   void  (*cb)(void *data, const E_Ofono_Element *element);
+   void *data;
+   void  (*free_data)(void *data);
+};
+
+static void
+_e_ofono_element_event_no_free(void *data __UNUSED__, void *ev)
+{
+   E_Ofono_Element *element = ev;
+   e_ofono_element_unref(element);
+}
+
+static void
+e_ofono_element_event_add(int event_type, E_Ofono_Element *element)
+{
+   e_ofono_element_ref(element);
+   ecore_event_add
+      (event_type, element, _e_ofono_element_event_no_free, element);
+}
+
+static void
+e_ofono_element_call_dispatch_and_free(void *d, DBusMessage *msg, DBusError *err)
+{
+   E_Ofono_Element_Call_Data *data = d;
+   E_Ofono_Element_Pending *pending;
+
+   pending = data->pending;
+   pending->pending = NULL;
+
+   if (data->cb)
+      data->cb(data->element, msg, err);
+
+   if (pending->user_cb)
+      pending->user_cb(pending->user_data, msg, err);
+
+   pending->data = NULL;
+   *data->p_list = eina_inlist_remove(*data->p_list, EINA_INLIST_GET(pending));
+   free(pending);
+   free(data);
+}
+
+static void
+e_ofono_element_pending_cancel_and_free(Eina_Inlist **pending)
+{
+   while (*pending)
+     {
+        E_Ofono_Element_Pending *p = (E_Ofono_Element_Pending *)*pending;
+        DBusError err;
+
+        dbus_pending_call_cancel(p->pending);
+
+        dbus_error_init(&err);
+        dbus_set_error(&err, "Canceled", "Pending method call was canceled.");
+        e_ofono_element_call_dispatch_and_free(p->data, NULL, &err);
+        dbus_error_free(&err);
+     }
+}
+
+void
+e_ofono_element_listener_add(E_Ofono_Element *element, void (*cb)(void *data, const E_Ofono_Element *element), const void *data, void (*free_data)(void *data))
+{
+   E_Ofono_Element_Listener *l;
+
+   if (!element)
+     {
+        ERR("safety check failed: element == NULL");
+        goto error;
+     }
+
+   if (!cb)
+     {
+        ERR("safety check failed: cb == NULL");
+        goto error;
+     }
+
+   l = malloc(sizeof(*l));
+   if (!l)
+     {
+        ERR("could not allocate E_Ofono_Element_Listener");
+        goto error;
+     }
+
+   l->cb = cb;
+   l->data = (void *)data;
+   l->free_data = free_data;
+
+   element->_listeners = eina_inlist_append
+         (element->_listeners, EINA_INLIST_GET(l));
+
+   return;
+
+error:
+   if (free_data)
+      free_data((void *)data);
+}
+
+void
+e_ofono_element_listener_del(E_Ofono_Element *element, void (*cb)(void *data, const E_Ofono_Element *element), const void *data)
+{
+   E_Ofono_Element_Listener *l;
+
+   EINA_SAFETY_ON_NULL_RETURN(element);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+
+   EINA_INLIST_FOREACH(element->_listeners, l)
+   if ((l->cb == cb) && (l->data == data))
+     {
+        element->_listeners = eina_inlist_remove
+              (element->_listeners, EINA_INLIST_GET(l));
+        if (l->free_data)
+           l->free_data(l->data);
+
+        free(l);
+        return;
+     }
+}
+
+static void
+_e_ofono_element_listeners_call_do(E_Ofono_Element *element)
+{
+   E_Ofono_Element_Listener *l, **shadow;
+   unsigned int i, count;
+
+   /* NB: iterate on a copy in order to allow listeners to be deleted
+    * from callbacks.  number of listeners should be small, so the
+    * following should do fine.
+    */
+   count = eina_inlist_count(element->_listeners);
+   if (count < 1)
+      goto end;
+
+   shadow = alloca(sizeof(*shadow) * count);
+   if (!shadow)
+      goto end;
+
+   i = 0;
+   EINA_INLIST_FOREACH(element->_listeners, l)
+   shadow[i++] = l;
+
+   for (i = 0; i < count; i++)
+      shadow[i]->cb(shadow[i]->data, element);
+
+end:
+   e_ofono_element_event_add(E_OFONO_EVENT_ELEMENT_UPDATED, element);
+}
+
+static Eina_Bool
+_e_ofono_element_listeners_call_idler(void *data)
+{
+   E_Ofono_Element *element = data;
+   _e_ofono_element_listeners_call_do(element);
+   element->_idler.changed = NULL;
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_e_ofono_element_listeners_call(E_Ofono_Element *element)
+{
+   if (element->_idler.changed)
+      return;
+
+   element->_idler.changed = ecore_idler_add
+         (_e_ofono_element_listeners_call_idler, element);
+}
+
+/***********************************************************************
+* Property
+***********************************************************************/
+
+static void
+_e_ofono_element_dict_entry_free(E_Ofono_Element_Dict_Entry *entry)
+{
+   switch (entry->type)
+     {
+      case DBUS_TYPE_BOOLEAN:
+      case DBUS_TYPE_BYTE:
+      case DBUS_TYPE_UINT16:
+      case DBUS_TYPE_UINT32:
+         break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+         eina_stringshare_del(entry->value.path);
+         break;
+
+      case DBUS_TYPE_STRING:
+         eina_stringshare_del(entry->value.str);
+         break;
+
+      default:
+         ERR("don't know how to free dict entry '%s' of type %c (%d)",
+             entry->name, entry->type, entry->type);
+     }
+
+   eina_stringshare_del(entry->name);
+   free(entry);
+}
+
+static E_Ofono_Element_Dict_Entry *
+_e_ofono_element_dict_entry_new(DBusMessageIter *itr)
+{
+   E_Ofono_Element_Dict_Entry *entry;
+   DBusMessageIter e_itr, v_itr;
+   int t;
+   const char *key = NULL;
+   void *value = NULL;
+
+   dbus_message_iter_recurse(itr, &e_itr);
+
+   t = dbus_message_iter_get_arg_type(&e_itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
+     {
+        ERR("invalid format for dict entry. first type not a string: %c (%d)",
+            t, t);
+        return NULL;
+     }
+
+   dbus_message_iter_get_basic(&e_itr, &key);
+   if (!key || !key[0])
+     {
+        ERR("invalid format for dict entry. no key.");
+        return NULL;
+     }
+
+   dbus_message_iter_next(&e_itr);
+   t = dbus_message_iter_get_arg_type(&e_itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_VARIANT))
+     {
+        ERR("invalid format for dict entry '%s'. "
+            "second type not a variant: %c (%d)",
+            key, t, t);
+        return NULL;
+     }
+
+   dbus_message_iter_recurse(&e_itr, &v_itr);
+
+   t = dbus_message_iter_get_arg_type(&v_itr);
+   if ((t == DBUS_TYPE_INVALID) || (t == DBUS_TYPE_ARRAY))
+     {
+        ERR("invalid type for dict value for entry '%s': %c (%d)",
+            key, t, t);
+        return NULL;
+     }
+
+   entry = calloc(1, sizeof(*entry));
+   if (!entry)
+     {
+        ERR("could not allocate memory for dict entry.");
+        return NULL;
+     }
+
+   dbus_message_iter_get_basic(&v_itr, &value);
+   switch (t)
+     {
+      case DBUS_TYPE_BOOLEAN:
+         entry->value.boolean = (Eina_Bool)(long)value;
+         break;
+
+      case DBUS_TYPE_BYTE:
+         entry->value.byte = (unsigned char)(long)value;
+         break;
+
+      case DBUS_TYPE_UINT16:
+         entry->value.u16 = (unsigned short)(long)value;
+         break;
+
+      case DBUS_TYPE_UINT32:
+         entry->value.u32 = (unsigned int)(long)value;
+         break;
+
+      case DBUS_TYPE_STRING:
+         entry->value.str = eina_stringshare_add(value);
+         break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+         entry->value.path = eina_stringshare_add(value);
+         break;
+
+      default:
+         ERR("don't know how to create dict entry '%s' for of type %c (%d)",
+             key, t, t);
+         free(entry);
+         return NULL;
+     }
+
+   entry->name = eina_stringshare_add(key);
+   entry->type = t;
+   return entry;
+}
+
+static E_Ofono_Element_Dict_Entry *
+_e_ofono_element_array_dict_find_stringshared(const E_Ofono_Array *array, const char *key)
+{
+   E_Ofono_Element_Dict_Entry *entry;
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+
+   EINA_ARRAY_ITER_NEXT(array->array, i, entry, iterator)
+   if (entry->name == key)
+      return entry;
+
+   return NULL;
+}
+
+static void
+_e_ofono_element_array_free(E_Ofono_Array *array, E_Ofono_Array *new __UNUSED__)
+{
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+   void *item;
+
+   if (!array)
+      return;
+
+   switch (array->type)
+     {
+      case DBUS_TYPE_BOOLEAN:
+      case DBUS_TYPE_BYTE:
+      case DBUS_TYPE_UINT16:
+      case DBUS_TYPE_UINT32:
+         break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         eina_stringshare_del(item);
+         break;
+
+      case DBUS_TYPE_STRING:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         eina_stringshare_del(item);
+         break;
+
+      case DBUS_TYPE_DICT_ENTRY:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         _e_ofono_element_dict_entry_free(item);
+         break;
+
+      default:
+         ERR("don't know how to free array of values of type %c (%d)",
+             array->type, array->type);
+         break;
+     }
+   eina_array_free(array->array);
+   free(array);
+}
+
+static void
+_e_ofono_element_property_value_free(E_Ofono_Element_Property *property)
+{
+   switch (property->type)
+     {
+      case 0:
+         return;
+
+      case DBUS_TYPE_BOOLEAN:
+      case DBUS_TYPE_BYTE:
+      case DBUS_TYPE_UINT16:
+      case DBUS_TYPE_UINT32:
+         break;
+
+      case DBUS_TYPE_STRING:
+         eina_stringshare_del(property->value.str);
+         break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+         eina_stringshare_del(property->value.path);
+         break;
+
+      case DBUS_TYPE_ARRAY:
+         _e_ofono_element_array_free(property->value.array, NULL);
+         break;
+
+      default:
+         ERR("don't know how to free value of property type %c (%d)",
+             property->type, property->type);
+     }
+}
+
+static const char *
+_e_ofono_element_get_interface(const char *key)
+{
+   const char *interface = NULL, *tail;
+   char head;
+
+   head = key[0];
+   tail = key + 1;
+
+   switch (head)
+     {
+      case 'M':
+         if (strcmp(tail, "odems") == 0)
+            interface = e_ofono_iface_modem;
+
+         break;
+
+      default:
+         break;
+     }
+
+   if (!interface)
+      ERR("failed to find interface for property \"%s\"", key);
+
+   return interface;
+}
+
+static E_Ofono_Element *
+_e_ofono_element_item_register(const char *key, const char *item)
+{
+   E_Ofono_Element *element;
+   const char *interface;
+
+   interface = _e_ofono_element_get_interface(key);
+   if (!interface)
+      return NULL;
+
+   element = e_ofono_element_register(item, interface);
+   if ((element) && (!e_ofono_element_properties_sync(element)))
+      WRN("could not get properties of %s", element->path);
+
+   return element;
+}
+
+/* Match 2 arrays to find which are new and which are old elements
+ * For new elements, register them under prop_name property
+ * For old elements, unregister them, sending proper DEL event
+ */
+static void
+_e_ofono_element_array_match(E_Ofono_Array *old, E_Ofono_Array *new, const char *prop_name, E_Ofono_Element *element)
+{
+   Eina_List *deleted = NULL;
+   Eina_Array_Iterator iter_old, iter_new;
+   unsigned int i_old = 0, i_new = 0;
+   void *item_old = NULL, *item_new;
+   Eina_List *l;
+   void *data;
+   Eina_Bool interfaces = EINA_FALSE;
+
+   if (!old)
+      return;
+
+   if ((old->type != DBUS_TYPE_OBJECT_PATH) &&
+       (old->type != DBUS_TYPE_STRING))
+      return;
+
+   /* is this a list of interfaces? */
+   interfaces = !strcmp(prop_name, "Interfaces");
+
+   if ((!new) || (!new->array) || eina_array_count(new->array) == 0)
+     {
+        if ((!old) || (!old->array) || eina_array_count(old->array) == 0)
+          {
+             return;
+          }
+        else
+          {
+             iter_old = old->array->data;
+             goto out_remove_remaining;
+          }
+     }
+
+   iter_new = new->array->data;
+   item_new = *iter_new;
+   EINA_ARRAY_ITER_NEXT(old->array, i_old, item_old, iter_old)
+   {
+      if (item_old == item_new)
+        {
+           i_new++;
+           if (i_new >= eina_array_count(new->array))
+             {
+                i_old++;
+                break;
+             }
+
+           iter_new++;
+           item_new = *iter_new;
+        }
+      else
+        {
+           deleted = eina_list_append(deleted, item_old);
+        }
+   }
+
+   for(; i_new < eina_array_count(new->array); iter_new++, i_new++)
+     {
+        Eina_Bool found = EINA_FALSE;
+        item_new = *iter_new;
+        if (!item_new)
+           break;
+
+        EINA_LIST_FOREACH(deleted, l, data)
+        {
+           if (data == item_new)
+             {
+                deleted = eina_list_remove_list(deleted, l);
+                found = EINA_TRUE;
+                break;
+             }
+        }
+        if (!found)
+          {
+             E_Ofono_Element *e = NULL;
+
+             if (interfaces)
+                e = e_ofono_element_register(item_new, element->path);
+             else
+                e = _e_ofono_element_item_register(prop_name, item_new);
+
+             if (e)
+                DBG("Add element %s (%s)\n", e->path, e->interface);
+          }
+     }
+
+   /* everybody after i_old on old->array + everybody from deleted list
+      will be removed
+    */
+   EINA_LIST_FREE(deleted, data)
+   {
+      E_Ofono_Element *e;
+      if (interfaces)
+         e = e_ofono_element_get(element->path, item_old);
+      else
+         e = e_ofono_element_get(data,
+                                 _e_ofono_element_get_interface(prop_name));
+
+      if (e)
+        {
+           e_ofono_element_unregister(e);
+           DBG("Deleted element %s %s\n", e->path, e->interface);
+        }
+   }
+
+out_remove_remaining:
+   for(; i_old < eina_array_count(old->array); iter_old++, i_old++)
+     {
+        E_Ofono_Element *e;
+        item_old = *iter_old;
+        if (!item_old)
+           break;
+
+        if (interfaces)
+           e = e_ofono_element_get(element->path, item_old);
+        else
+           e = e_ofono_element_get(item_old,
+                                   _e_ofono_element_get_interface(prop_name));
+
+        if (e)
+          {
+             e_ofono_element_unregister(e);
+             DBG("Deleted element %s %s\n", e->path, e->interface);
+          }
+     }
+}
+
+static Eina_Bool
+_e_ofono_element_property_update(E_Ofono_Element_Property *property, int type, void *data, E_Ofono_Element *element)
+{
+   Eina_Bool changed = EINA_FALSE;
+
+   if ((type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) && data)
+      data = (char *)eina_stringshare_add(data);
+
+   if (property->type != type)
+     {
+        if (property->type)
+           DBG("property type changed from '%c' to '%c'",
+               property->type, type);
+
+        _e_ofono_element_property_value_free(property);
+        memset(&property->value, 0, sizeof(property->value));
+        property->type = type;
+        changed = EINA_TRUE;
+     }
+
+   switch (type)
+     {
+      case DBUS_TYPE_BOOLEAN:
+         if (changed || property->value.boolean != (Eina_Bool)(long)data)
+           {
+              property->value.boolean = (Eina_Bool)(long)data;
+              changed = EINA_TRUE;
+           }
+
+         break;
+
+      case DBUS_TYPE_BYTE:
+         if (changed || property->value.byte != (unsigned char)(long)data)
+           {
+              property->value.byte = (unsigned char)(long)data;
+              changed = EINA_TRUE;
+           }
+
+         break;
+
+      case DBUS_TYPE_UINT16:
+         if (changed || property->value.u16 != (unsigned short)(long)data)
+           {
+              property->value.u16 = (unsigned short)(long)data;
+              changed = EINA_TRUE;
+           }
+
+         break;
+
+      case DBUS_TYPE_UINT32:
+         if (changed || property->value.u32 != (unsigned int)(long)data)
+           {
+              property->value.u32 = (unsigned int)(long)data;
+              changed = EINA_TRUE;
+           }
+
+         break;
+
+      case DBUS_TYPE_STRING:
+         if (changed)
+           {
+              property->value.str = data;
+           }
+         else
+           {
+              if (property->value.str)
+                 eina_stringshare_del(property->value.str);
+
+              if (property->value.str != data)
+                {
+                   property->value.str = data;
+                   changed = EINA_TRUE;
+                }
+           }
+
+         break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+         if (changed)
+           {
+              property->value.path = data;
+           }
+         else
+           {
+              if (property->value.path)
+                 eina_stringshare_del(property->value.path);
+
+              if (property->value.path != data)
+                {
+                   property->value.path = data;
+                   changed = EINA_TRUE;
+                }
+           }
+
+         break;
+
+      case DBUS_TYPE_ARRAY:
+         if (!changed)
+            if (property->value.array)
+              {
+                 _e_ofono_element_array_match(property->value.array, data,
+                                              property->name, element);
+                 _e_ofono_element_array_free(property->value.array, data);
+              }
+
+         property->value.array = data;
+         changed = EINA_TRUE;
+         break;
+
+      default:
+         ERR("don't know how to update property type %c (%d)", type, type);
+     }
+
+   return changed;
+}
+
+static E_Ofono_Element_Property *
+_e_ofono_element_property_new(const char *name, int type, void *data, E_Ofono_Element *element)
+{
+   E_Ofono_Element_Property *property;
+
+   property = calloc(1, sizeof(*property));
+   if (!property)
+     {
+        eina_stringshare_del(name);
+        ERR("could not allocate property: %s", strerror(errno));
+        return NULL;
+     }
+
+   property->name = name;
+   _e_ofono_element_property_update(property, type, data, element);
+   return property;
+}
+
+static void
+_e_ofono_element_property_free(E_Ofono_Element_Property *property)
+{
+   _e_ofono_element_property_value_free(property);
+   eina_stringshare_del(property->name);
+   free(property);
+}
+
+/***********************************************************************
+* Element
+***********************************************************************/
+unsigned char *
+e_ofono_element_bytes_array_get_stringshared(const E_Ofono_Element *element, const char *property, unsigned int *count)
+{
+   Eina_Array_Iterator iterator;
+   E_Ofono_Array *array;
+   unsigned char *ret, *p;
+   unsigned int i;
+   void *item;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(property, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, NULL);
+
+   *count = 0;
+
+   if (!e_ofono_element_property_get_stringshared
+          (element, property, NULL, &array))
+      return NULL;
+
+   if ((!array) || (!(array->array)))
+      return NULL;
+
+   *count = eina_array_count(array->array);
+   ret = malloc(*count * sizeof(unsigned char));
+   if (!ret)
+     {
+        ERR("could not allocate return array of %d bytes: %s",
+            *count, strerror(errno));
+        return NULL;
+     }
+
+   p = ret;
+
+   EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+   {
+      *p = (unsigned char)(long)item;
+      p++;
+   }
+   return ret;
+}
+
+Eina_Bool
+e_ofono_element_objects_array_get_stringshared(const E_Ofono_Element *element, const char *property, unsigned int *count, E_Ofono_Element ***p_elements)
+{
+   E_Ofono_Element **ret, **p;
+   Eina_Array_Iterator iterator;
+   E_Ofono_Array *array;
+   unsigned int i;
+   int type;
+   void *item;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(property, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
+
+   *count = 0;
+   *p_elements = NULL;
+
+   if (!e_ofono_element_property_get_stringshared
+          (element, property, &type, &array))
+      return EINA_FALSE;
+
+   if (type != DBUS_TYPE_ARRAY)
+     {
+        ERR("property %s is not an array!", property);
+        return EINA_FALSE;
+     }
+
+   if ((!array) || (!array->array) || (array->type == DBUS_TYPE_INVALID))
+      return EINA_FALSE;
+
+   if (array->type != DBUS_TYPE_OBJECT_PATH)
+     {
+        ERR("property %s is not an array of object paths!", property);
+        return EINA_FALSE;
+     }
+
+   *count = eina_array_count(array->array);
+   ret = malloc(*count * sizeof(E_Ofono_Element *));
+   if (!ret)
+     {
+        ERR("could not allocate return array of %d elements: %s",
+            *count, strerror(errno));
+        *count = 0;
+        return EINA_FALSE;
+     }
+
+   p = ret;
+
+   EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+   {
+      E_Ofono_Element *e = e_ofono_element_get(item, property);
+      if (!e)
+         continue;
+
+      *p = e;
+      p++;
+   }
+   *count = p - ret;
+   *p_elements = ret;
+   return EINA_TRUE;
+}
+
+/* strings are just pointers (references), no strdup or stringshare_add/ref */
+Eina_Bool
+e_ofono_element_strings_array_get_stringshared(const E_Ofono_Element *element, const char *property, unsigned int *count, const char ***strings)
+{
+   const char **ret, **p;
+   Eina_Array_Iterator iterator;
+   E_Ofono_Array *array;
+   unsigned int i;
+   int type;
+   void *item;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(property, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(strings, EINA_FALSE);
+
+   *count = 0;
+   *strings = NULL;
+
+   if (!e_ofono_element_property_get_stringshared
+          (element, property, &type, &array))
+      return EINA_FALSE;
+
+   if (type != DBUS_TYPE_ARRAY)
+     {
+        ERR("property %s is not an array!", property);
+        return EINA_FALSE;
+     }
+
+   if ((!array) || (!array->array) || (array->type == DBUS_TYPE_INVALID))
+      return EINA_FALSE;
+
+   if (array->type != DBUS_TYPE_STRING)
+     {
+        ERR("property %s is not an array of strings!", property);
+        return EINA_FALSE;
+     }
+
+   *count = eina_array_count(array->array);
+   ret = malloc(*count * sizeof(char *));
+   if (!ret)
+     {
+        ERR("could not allocate return array of %d strings: %s",
+            *count, strerror(errno));
+        *count = 0;
+        return EINA_FALSE;
+     }
+
+   p = ret;
+
+   EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+   {
+      if (!item)
+         continue;
+
+      *p = item;
+      p++;
+   }
+   *count = p - ret;
+   *strings = ret;
+   return EINA_TRUE;
+}
+
+static void
+_e_ofono_element_array_print(FILE *fp, E_Ofono_Array *array)
+{
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+   void *item;
+
+   if (!array)
+      return;
+
+   switch (array->type)
+     {
+      case DBUS_TYPE_OBJECT_PATH:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "\"%s\", ", (const char *)item);
+         break;
+
+      case DBUS_TYPE_STRING:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "\"%s\", ", (const char *)item);
+         break;
+
+      case DBUS_TYPE_BYTE:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "%#02hhx (\"%c\"), ", (unsigned char)(long)item,
+                 (unsigned char)(long)item);
+         break;
+
+      case DBUS_TYPE_UINT16:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "%#04hx (%hu), ", (unsigned short)(long)item,
+                 (unsigned short)(long)item);
+         break;
+
+      case DBUS_TYPE_UINT32:
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         fprintf(fp, "%#08x (%u), ", (unsigned int)(long)item,
+                 (unsigned int)(long)item);
+         break;
+
+      case DBUS_TYPE_DICT_ENTRY:
+         fputs("{ ", fp);
+         EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
+         {
+            E_Ofono_Element_Dict_Entry *entry = item;
+            fprintf(fp, "%s: ", entry->name);
+            switch (entry->type)
+              {
+               case DBUS_TYPE_OBJECT_PATH:
+                  fprintf(fp, "\"%s\", ", entry->value.path);
+                  break;
+
+               case DBUS_TYPE_STRING:
+                  fprintf(fp, "\"%s\", ", entry->value.str);
+                  break;
+
+               case DBUS_TYPE_BYTE:
+                  fprintf(fp, "%#02hhx (\"%c\"), ",
+                          entry->value.byte, entry->value.byte);
+                  break;
+
+               case DBUS_TYPE_UINT16:
+                  fprintf(fp, "%#04hx (%hu), ",
+                          entry->value.u16, entry->value.u16);
+                  break;
+
+               case DBUS_TYPE_UINT32:
+                  fprintf(fp, "%#08x (%u), ",
+                          entry->value.u32, entry->value.u32);
+                  break;
+
+               default:
+                  fprintf(fp, "<UNKNOWN TYPE '%c'>", entry->type);
+              }
+         }
+         fputs("}", fp);
+         break;
+
+      default:
+         fprintf(fp, "<UNKNOWN ARRAY TYPE '%c'>", array->type);
+     }
+}
+
+/**
+ * Print element to file descriptor.
+ */
+void
+e_ofono_element_print(FILE *fp, const E_Ofono_Element *element)
+{
+   const E_Ofono_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN(fp);
+   if (!element)
+     {
+        fputs("Error: no element to print\n", fp);
+        return;
+     }
+
+   fprintf(fp,
+           "Element %p: %s [%s]\n"
+           "\tProperties:\n",
+           element, element->path, element->interface);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      fprintf(fp, "\t\t%s (%c) = ", p->name, p->type);
+
+      switch (p->type)
+        {
+         case DBUS_TYPE_STRING:
+            fprintf(fp, "\"%s\"", p->value.str);
+            break;
+
+         case DBUS_TYPE_OBJECT_PATH:
+            fprintf(fp, "\"%s\"", p->value.path);
+            break;
+
+         case DBUS_TYPE_BOOLEAN:
+            fprintf(fp, "%hhu", p->value.boolean);
+            break;
+
+         case DBUS_TYPE_BYTE:
+            fprintf(fp, "%#02hhx (%d), ", p->value.byte, p->value.byte);
+            break;
+
+         case DBUS_TYPE_UINT16:
+            fprintf(fp, "%hu", p->value.u16);
+            break;
+
+         case DBUS_TYPE_UINT32:
+            fprintf(fp, "%u", p->value.u32);
+            break;
+
+         case DBUS_TYPE_ARRAY:
+            _e_ofono_element_array_print(fp, p->value.array);
+            break;
+
+         default:
+            fputs("don't know how to print type", fp);
+        }
+
+      fputc('\n', fp);
+   }
+}
+
+static E_Ofono_Element *
+e_ofono_element_new(const char *path, const char *interface)
+{
+   E_Ofono_Element *element;
+
+   element = calloc(1, sizeof(*element));
+   if (!element)
+     {
+        ERR("could not allocate element: %s",   strerror(errno));
+        return NULL;
+     }
+
+   element->path = eina_stringshare_add(path);
+   element->interface = eina_stringshare_ref(interface);
+   element->_references = 1;
+
+   return element;
+}
+
+static void
+e_ofono_element_extra_properties_free(E_Ofono_Element *element)
+{
+   while (element->props)
+     {
+        E_Ofono_Element_Property *prop;
+        prop = (E_Ofono_Element_Property *)element->props;
+        element->props = element->props->next;
+        _e_ofono_element_property_free(prop);
+     }
+}
+
+static void
+e_ofono_element_free(E_Ofono_Element *element)
+{
+   if (element->_idler.changed)
+      ecore_idler_del(element->_idler.changed);
+
+   while (element->_listeners)
+     {
+        E_Ofono_Element_Listener *l = (void *)element->_listeners;
+        element->_listeners = eina_inlist_remove
+              (element->_listeners, element->_listeners);
+
+        if (l->free_data)
+           l->free_data(l->data);
+
+        free(l);
+     }
+
+   e_ofono_element_pending_cancel_and_free(&element->_pending.properties_get);
+   e_ofono_element_pending_cancel_and_free(&element->_pending.property_set);
+   e_ofono_element_pending_cancel_and_free(&element->_pending.send_sms);
+
+   e_ofono_element_extra_properties_free(element);
+   eina_stringshare_del(element->interface);
+   eina_stringshare_del(element->path);
+   free(element);
+}
+
+/**
+ * Add reference to element.
+ */
+int
+e_ofono_element_ref(E_Ofono_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, 0);
+   return ++element->_references;
+}
+
+/**
+ * Remove reference from element.
+ *
+ * If reference count drops to 0 element will be freed.
+ */
+int
+e_ofono_element_unref(E_Ofono_Element *element)
+{
+   int i;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, 0);
+
+   i = --element->_references;
+   if (i == 0)
+      e_ofono_element_free(element);
+   else if (i < 0)
+      ERR("element %p references %d < 0", element, i);
+
+   return i;
+}
+
+/**
+ * Send message with callbacks set to work with ofono elements.
+ *
+ * If this call fails (returns 0), pending callbacks will not be called,
+ * not even with error messages.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_element_message_send(E_Ofono_Element *element, const char *method_name, const char *interface, E_DBus_Method_Return_Cb cb, DBusMessage *msg, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
+{
+   E_Ofono_Element_Call_Data *data;
+   E_Ofono_Element_Pending *p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(msg, EINA_FALSE);
+
+   interface = interface ? : element->interface;
+
+   data = malloc(sizeof(*data));
+   if (!data)
+     {
+        ERR("could not alloc e_ofono_element_call_data: %s",
+            strerror(errno));
+        dbus_message_unref(msg);
+        return EINA_FALSE;
+     }
+
+   p = malloc(sizeof(*p));
+   if (!p)
+     {
+        ERR("could not alloc E_Ofono_Element_Pending: %s",
+            strerror(errno));
+        free(data);
+        dbus_message_unref(msg);
+        return EINA_FALSE;
+     }
+
+   data->element = element;
+   data->cb = cb;
+   data->pending = p;
+   data->p_list = pending;
+   p->user_cb = user_cb;
+   p->user_data = (void *)user_data;
+   p->data = data;
+   p->pending = e_dbus_message_send
+         (e_ofono_conn, msg, e_ofono_element_call_dispatch_and_free, -1, data);
+   dbus_message_unref(msg);
+
+   if (p->pending)
+     {
+        *pending = eina_inlist_append(*pending, EINA_INLIST_GET(p));
+        return EINA_TRUE;
+     }
+
+   ERR("failed to call %s (obj=%s, path=%s, iface=%s)",
+       method_name, e_ofono_system_bus_name_get(),
+       element->path, interface);
+   free(data);
+   free(p);
+   return EINA_FALSE;
+}
+
+Eina_Bool
+e_ofono_element_call_full(E_Ofono_Element *element, const char *method_name, const char *interface, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
+{
+   DBusMessage *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
+
+   interface = interface ? : element->interface;
+
+   msg = dbus_message_new_method_call
+         (e_ofono_system_bus_name_get(), element->path, interface,
+         method_name);
+
+   return e_ofono_element_message_send
+             (element, method_name, interface, cb, msg, pending, user_cb, user_data);
+}
+
+static Eina_Bool
+_e_ofono_element_property_value_add(E_Ofono_Element *element, const char *name, int type, void *value)
+{
+   E_Ofono_Element_Property *p;
+
+   name = eina_stringshare_add(name);
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      if (p->name == name)
+        {
+           eina_stringshare_del(name);
+           return _e_ofono_element_property_update(p, type, value, element);
+        }
+   }
+
+   p = _e_ofono_element_property_new(name, type, value, element);
+   if (!p)
+     {
+        ERR("could not create property %s (%c)", name, type);
+        return EINA_FALSE;
+     }
+
+   element->props = eina_inlist_append(element->props, EINA_INLIST_GET(p));
+   return EINA_TRUE;
+}
+
+static E_Ofono_Array *
+_e_ofono_element_iter_get_array(DBusMessageIter *itr, const char *key)
+{
+   E_Ofono_Array *array;
+   DBusMessageIter e_itr;
+
+   array = malloc(sizeof(E_Ofono_Array));
+   if (!array)
+     {
+        ERR("could not create new e_ofono array.");
+        return NULL;
+     }
+
+   array->array = eina_array_new(16);
+   if (!(array->array))
+     {
+        ERR("could not create new eina array.");
+        free(array);
+        return NULL;
+     }
+
+   dbus_message_iter_recurse(itr, &e_itr);
+   array->type = dbus_message_iter_get_arg_type(&e_itr);
+   if (array->type == DBUS_TYPE_INVALID)
+     {
+        DBG("array %s is of type 'invalid' (empty?)", key);
+        eina_array_free(array->array);
+        free(array);
+        return NULL;
+     }
+
+   do
+     {
+        switch (array->type)
+          {
+           case DBUS_TYPE_OBJECT_PATH:
+           {
+              const char *path;
+
+              dbus_message_iter_get_basic(&e_itr, &path);
+              path = eina_stringshare_add(path);
+              eina_array_push(array->array, path);
+              _e_ofono_element_item_register(key, path);
+           }
+           break;
+
+           case DBUS_TYPE_STRING:
+           {
+              const char *str;
+
+              dbus_message_iter_get_basic(&e_itr, &str);
+              str = eina_stringshare_add(str);
+              eina_array_push(array->array, str);
+           }
+           break;
+
+           case DBUS_TYPE_BYTE:
+           {
+              unsigned char byte;
+              dbus_message_iter_get_basic(&e_itr, &byte);
+              eina_array_push(array->array, (void *)(long)byte);
+           }
+           break;
+
+           case DBUS_TYPE_DICT_ENTRY:
+           {
+              E_Ofono_Element_Dict_Entry *entry;
+              entry = _e_ofono_element_dict_entry_new(&e_itr);
+              if (entry)
+                 eina_array_push(array->array, entry);
+           }
+           break;
+
+           default:
+              ERR("don't know how to build array '%s' of type %c (%d)",
+                  key, array->type, array->type);
+              eina_array_free(array->array);
+              free(array);
+              return NULL;
+          }
+     }
+   while (dbus_message_iter_next(&e_itr));
+   return array;
+}
+
+static void
+_e_ofono_element_get_properties_callback(void *user_data, DBusMessage *msg, DBusError *err)
+{
+   E_Ofono_Element *element = user_data;
+   DBusMessageIter itr, s_itr;
+   int t, changed;
+
+   DBG("get_properties msg=%p", msg);
+
+   if (!_dbus_callback_check_and_init(msg, &itr, err))
+      return;
+
+   t = dbus_message_iter_get_arg_type(&itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_ARRAY))
+      return;
+
+   changed = 0;
+   dbus_message_iter_recurse(&itr, &s_itr);
+   do
+     {
+        DBusMessageIter e_itr, v_itr;
+        const char *key;
+        void *value = NULL;
+        int r;
+
+        t = dbus_message_iter_get_arg_type(&s_itr);
+        if (!_dbus_iter_type_check(t, DBUS_TYPE_DICT_ENTRY))
+           continue;
+
+        dbus_message_iter_recurse(&s_itr, &e_itr);
+
+        t = dbus_message_iter_get_arg_type(&e_itr);
+        if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
+           continue;
+
+        dbus_message_iter_get_basic(&e_itr, &key);
+        dbus_message_iter_next(&e_itr);
+        t = dbus_message_iter_get_arg_type(&e_itr);
+        if (!_dbus_iter_type_check(t, DBUS_TYPE_VARIANT))
+           continue;
+
+        dbus_message_iter_recurse(&e_itr, &v_itr);
+        t = dbus_message_iter_get_arg_type(&v_itr);
+        if (t == DBUS_TYPE_ARRAY)
+          {
+             value = _e_ofono_element_iter_get_array(&v_itr, key);
+          }
+        else if (t != DBUS_TYPE_INVALID)
+          {
+             dbus_message_iter_get_basic(&v_itr, &value);
+          }
+        else
+          {
+             ERR("property has invalid type %s", key);
+             continue;
+          }
+
+        r = _e_ofono_element_property_value_add(element, key, t, value);
+        if (r < 0)
+          {
+             ERR("failed to add property value %s (%c)", key, t);
+          }
+        else if (r == 1)
+          {
+             INF("property value changed %s (%c)", key, t);
+             changed = 1;
+             if ((strcmp(key, "Interfaces") == 0) && value)
+               {
+                  char *interface;
+                  Eina_Array_Iterator iterator;
+                  unsigned int i;
+                  E_Ofono_Element *e;
+
+                  EINA_ARRAY_ITER_NEXT(((E_Ofono_Array *)value)->array, i,
+                                       interface, iterator)
+                  {
+                     DBG("Found interface %s on %s", interface, element->path);
+                     e = e_ofono_element_register(element->path, interface);
+                     if ((e) && (!e_ofono_element_properties_sync(e)))
+                        WRN("could not get properties of %s", e->path);
+                  }
+               }
+          }
+     }
+   while (dbus_message_iter_next(&s_itr));
+
+   if (changed)
+      _e_ofono_element_listeners_call(element);
+}
+
+/**
+ * Sync element properties with server.
+ *
+ * Call method GetProperties() at the given element on server in order to sync
+ * them.
+ *
+ * @param element to call method on server.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_element_sync_properties_full(E_Ofono_Element *element, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "GetProperties";
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return e_ofono_element_call_full
+             (element, name, element->interface,
+             _e_ofono_element_get_properties_callback,
+             &element->_pending.properties_get, cb, data);
+}
+
+/**
+ * Sync element properties with server, simple version.
+ *
+ * Call method GetProperties() at the given element on server in order to sync
+ * them. This is the simple version and there is no check of server reply
+ * for errors.
+ *
+ * @param element to call method on server.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_element_properties_sync(E_Ofono_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return e_ofono_element_sync_properties_full(element, NULL, NULL);
+}
+
+/**
+ * Call method SetProperty(prop, {key: value}) at the given element on server.
+ *
+ * This is a server call, not local, so it may fail and in that case
+ * no property is updated locally. If the value was set the event
+ * E_OFONO_EVENT_ELEMENT_UPDATED will be added to main loop.
+ *
+ * @param element to call method on server.
+ * @param prop property name.
+ * @param key dict key name.
+ * @param type DBus type to use for value.
+ * @param value pointer to value, just like regular DBus, see
+ *        dbus_message_iter_append_basic().
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_element_property_dict_set_full(E_Ofono_Element *element, const char *prop, const char *key, int type, const void *value, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "SetProperty";
+   DBusMessage *msg;
+   DBusMessageIter itr, variant, dict, entry;
+   char typestr[32];
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_ofono_system_bus_name_get(), element->path, element->interface, name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &prop);
+
+   if ((size_t)snprintf(typestr, sizeof(typestr),
+                        (DBUS_TYPE_ARRAY_AS_STRING
+                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                         DBUS_TYPE_STRING_AS_STRING
+                         "%c"
+                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
+                        type) >= sizeof(typestr))
+     {
+        ERR("sizeof(typestr) is too small!");
+        return EINA_FALSE;
+     }
+
+   if (dbus_message_iter_open_container(&itr, DBUS_TYPE_VARIANT, typestr, &variant))
+     {
+        snprintf(typestr, sizeof(typestr),
+                 (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                     DBUS_TYPE_STRING_AS_STRING
+                     "%c"
+                     DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
+                 type);
+        
+        if (dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, typestr, &dict))
+          {
+             if (dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry))
+               {
+                  dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+                  
+                  if ((type == DBUS_TYPE_STRING) || (type == DBUS_TYPE_OBJECT_PATH))
+                    dbus_message_iter_append_basic(&entry, type, &value);
+                  else
+                    dbus_message_iter_append_basic(&entry, type, value);
+                  
+                  dbus_message_iter_close_container(&dict, &entry);
+               }
+             else
+               {
+                  ERR("dbus_message_iter_open_container() failed");
+               }
+             dbus_message_iter_close_container(&variant, &dict);
+          }
+        else
+          {
+             ERR("dbus_message_iter_open_container() failed");
+          }
+        dbus_message_iter_close_container(&itr, &variant);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+
+   return e_ofono_element_message_send
+             (element, name, NULL, NULL, msg,
+             &element->_pending.property_set, cb, data);
+}
+
+/**
+ * Call method SetProperty(prop, value) at the given element on server.
+ *
+ * This is a server call, not local, so it may fail and in that case
+ * no property is updated locally. If the value was set the event
+ * E_OFONO_EVENT_ELEMENT_UPDATED will be added to main loop.
+ *
+ * @param element to call method on server.
+ * @param prop property name.
+ * @param type DBus type to use for value.
+ * @param value pointer to value, just like regular DBus, see
+ *        dbus_message_iter_append_basic().
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_element_property_set_full(E_Ofono_Element *element, const char *prop, int type, const void *value, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   const char name[] = "SetProperty";
+   char typestr[2];
+   DBusMessage *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_ofono_system_bus_name_get(), element->path, element->interface, name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   DBusMessageIter itr, v;
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &prop);
+
+   typestr[0] = type;
+   typestr[1] = '\0';
+   dbus_message_iter_open_container(&itr, DBUS_TYPE_VARIANT, typestr, &v);
+   if ((type == DBUS_TYPE_STRING) || (type == DBUS_TYPE_OBJECT_PATH))
+     {
+        dbus_message_iter_append_basic(&v, type, &value);
+     }
+   else if (type == DBUS_TYPE_BOOLEAN)
+     {
+        unsigned int b = *(Eina_Bool *)value;
+        dbus_message_iter_append_basic(&v, type, &b);
+     }
+   else
+     {
+        dbus_message_iter_append_basic(&v, type, value);
+     }
+
+   dbus_message_iter_close_container(&itr, &v);
+
+   return e_ofono_element_message_send
+             (element, name, NULL, NULL, msg,
+             &element->_pending.property_set, cb, data);
+}
+
+/**
+ * Call method SetProperty(prop, value) at the given element on server.
+ *
+ * This is the simple version and there is no check of server reply
+ * for errors.
+ *
+ * @param element to call method on server.
+ * @param prop property name.
+ * @param type DBus type to use for value.
+ * @param value pointer to value, just like regular DBus, see
+ *        dbus_message_iter_append_basic().
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_element_property_set(E_Ofono_Element *element, const char *prop, int type, const void *value)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
+   return e_ofono_element_property_set_full
+             (element, prop, type, value, NULL, NULL);
+}
+
+Eina_Bool
+e_ofono_element_call_with_path(E_Ofono_Element *element, const char *method_name, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
+{
+   DBusMessageIter itr;
+   DBusMessage *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_ofono_system_bus_name_get(), element->path, element->interface,
+         method_name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_OBJECT_PATH, &string);
+
+   return e_ofono_element_message_send
+             (element, method_name, NULL, cb, msg, pending, user_cb, user_data);
+}
+
+Eina_Bool
+e_ofono_element_call_with_string(E_Ofono_Element *element, const char *method_name, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
+{
+   DBusMessageIter itr;
+   DBusMessage *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_ofono_system_bus_name_get(), element->path, element->interface,
+         method_name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &string);
+
+   return e_ofono_element_message_send
+             (element, method_name, NULL, cb, msg, pending, user_cb, user_data);
+}
+
+Eina_Bool
+e_ofono_element_call_with_path_and_string(E_Ofono_Element *element, const char *method_name, const char *path, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
+{
+   DBusMessageIter itr;
+   DBusMessage *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
+
+   msg = dbus_message_new_method_call
+         (e_ofono_system_bus_name_get(), element->path, element->interface,
+         method_name);
+
+   if (!msg)
+      return EINA_FALSE;
+
+   dbus_message_iter_init_append(msg, &itr);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_OBJECT_PATH, &path);
+   dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &string);
+
+   return e_ofono_element_message_send
+             (element, method_name, NULL, cb, msg, pending, user_cb, user_data);
+}
+
+/**
+ * Get property type.
+ *
+ * If zero is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param name property name, must be previously stringshared
+ * @param type will contain the value type.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_element_property_type_get_stringshared(const E_Ofono_Element *element, const char *name, int *type)
+{
+   const E_Ofono_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      if (p->name == name)
+        {
+           *type = p->type;
+           return EINA_TRUE;
+        }
+   }
+
+   WRN("element %s (%p) has no property with name \"%s\".",
+       element->path, element, name);
+   return EINA_FALSE;
+}
+
+/**
+ * Get property type.
+ *
+ * If zero is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param name property name
+ * @param type will contain the value type.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_element_property_type_get(const E_Ofono_Element *element, const char *name, int *type)
+{
+   Eina_Bool ret;
+   name = eina_stringshare_add(name);
+   ret = e_ofono_element_property_type_get_stringshared(element, name, type);
+   eina_stringshare_del(name);
+   return ret;
+}
+
+void
+e_ofono_element_list_properties(const E_Ofono_Element *element, Eina_Bool (*cb)(void *data, const E_Ofono_Element *element, const char *name, int type, const void *value), const void *data)
+{
+   const E_Ofono_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN(element);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      const void *value = NULL;
+
+      switch (p->type)
+        {
+         case DBUS_TYPE_STRING:
+            value = &p->value.str;
+            break;
+
+         case DBUS_TYPE_OBJECT_PATH:
+            value = &p->value.path;
+            break;
+
+         case DBUS_TYPE_BOOLEAN:
+            value = (void *)(unsigned long)p->value.boolean;
+            break;
+
+         case DBUS_TYPE_UINT16:
+            value = &p->value.u16;
+            break;
+
+         case DBUS_TYPE_UINT32:
+            value = &p->value.u32;
+            break;
+
+         default:
+            ERR("unsupported type %c", p->type);
+        }
+
+      if (!cb((void *)data, element, p->name, p->type, value))
+         return;
+   }
+}
+
+/**
+ * Get dict value given its key inside a dict property.
+ *
+ * This will look into properties for one of type dict that contains
+ * the given key, to find the property.  If no property is found then
+ * 0 is returned.
+ *
+ * If zero is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param dict_name property name, must be previously stringshared
+ * @param key key inside dict, must be previously stringshared
+ * @param type if provided it will contain the value type.
+ * @param value where to store the property value, must be a pointer to the
+ *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_element_property_dict_get_stringshared(const E_Ofono_Element *element, const char *dict_name, const char *key, int *type, void *value)
+{
+   const E_Ofono_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dict_name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      E_Ofono_Element_Dict_Entry *entry;
+      E_Ofono_Array *array;
+
+      if (p->name != dict_name)
+         continue;
+
+      if (p->type != DBUS_TYPE_ARRAY)
+        {
+           WRN("element %s (%p) has property \"%s\" is not an array: %c (%d)",
+               element->path, element, dict_name, p->type, p->type);
+           return EINA_FALSE;
+        }
+
+      array = p->value.array;
+      if ((!array) || (array->type != DBUS_TYPE_DICT_ENTRY))
+        {
+           int t = array ? array->type : DBUS_TYPE_INVALID;
+           WRN("element %s (%p) has property \"%s\" is not a dict: %c (%d)",
+               element->path, element, dict_name, t, t);
+           return EINA_FALSE;
+        }
+
+      entry = _e_ofono_element_array_dict_find_stringshared(array, key);
+      if (!entry)
+        {
+           WRN("element %s (%p) has no dict property with name \"%s\" with "
+               "key \"%s\".",
+               element->path, element, dict_name, key);
+           return EINA_FALSE;
+        }
+
+      if (type)
+         *type = entry->type;
+
+      switch (entry->type)
+        {
+         case DBUS_TYPE_BOOLEAN:
+            *(Eina_Bool *)value = entry->value.boolean;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_BYTE:
+            *(unsigned char *)value = entry->value.byte;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_UINT16:
+            *(unsigned short *)value = entry->value.u16;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_UINT32:
+            *(unsigned int *)value = entry->value.u32;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_STRING:
+            *(const char **)value = entry->value.str;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_OBJECT_PATH:
+            *(const char **)value = entry->value.path;
+            return EINA_TRUE;
+
+         default:
+            ERR("don't know how to get property %s, key %s type %c (%d)",
+                dict_name, key, entry->type, entry->type);
+            return EINA_FALSE;
+        }
+   }
+
+   WRN("element %s (%p) has no property with name \"%s\".",
+       element->path, element, dict_name);
+   return EINA_FALSE;
+}
+
+/**
+ * Get property value given its name.
+ *
+ * This will look into properties, to find the property.
+ * If no property is found then 0 is returned.
+ *
+ * If zero is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param name property name, must be previously stringshared
+ * @param type if provided it will contain the value type.
+ * @param value where to store the property value, must be a pointer to the
+ *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_element_property_get_stringshared(const E_Ofono_Element *element, const char *name, int *type, void *value)
+{
+   const E_Ofono_Element_Property *p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
+
+   EINA_INLIST_FOREACH(element->props, p)
+   {
+      if (p->name != name)
+         continue;
+
+      if (type)
+         *type = p->type;
+
+      switch (p->type)
+        {
+         case DBUS_TYPE_BOOLEAN:
+            *(Eina_Bool *)value = p->value.boolean;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_BYTE:
+            *(unsigned char *)value = p->value.byte;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_UINT16:
+            *(unsigned short *)value = p->value.u16;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_UINT32:
+            *(unsigned int *)value = p->value.u32;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_STRING:
+            *(const char **)value = p->value.str;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_OBJECT_PATH:
+            *(const char **)value = p->value.path;
+            return EINA_TRUE;
+
+         case DBUS_TYPE_ARRAY:
+            *(E_Ofono_Array **)value = p->value.array;
+            return EINA_TRUE;
+
+         default:
+            ERR("don't know how to get property type %c (%d)",
+                p->type, p->type);
+            return EINA_FALSE;
+        }
+   }
+
+   WRN("element %s (%p) has no property with name \"%s\".",
+       element->path, element, name);
+   return EINA_FALSE;
+}
+
+/**
+ * Get property value given its name.
+ *
+ * This will look into properties, to find the property.
+ * If no property is found then 0 is returned.
+ *
+ * If zero is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param element which element to get the property
+ * @param name property name
+ * @param type if provided it will contain the value type.
+ * @param value where to store the property value, must be a pointer to the
+ *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_element_property_get(const E_Ofono_Element *element, const char *name, int *type, void *value)
+{
+   Eina_Bool ret;
+   name = eina_stringshare_add(name);
+   ret = e_ofono_element_property_get_stringshared
+         (element, name, type, value);
+   eina_stringshare_del(name);
+   return ret;
+}
+
+struct e_ofono_elements_for_each_data
+{
+   Eina_Hash_Foreach cb;
+   void             *data;
+};
+
+static Eina_Bool
+_e_ofono_elements_for_each(Eina_Hash *hash __UNUSED__, const char *key, void *data, void *fdata)
+{
+   struct e_ofono_elements_for_each_data *each_data = fdata;
+
+   each_data->cb(elements, key, data, each_data->data);
+   return EINA_TRUE;
+}
+
+/**
+ * Call the given function for each existing element.
+ *
+ * @param cb function to call for each element. It will get as parameters,
+ *        in order: the element pointer and the given @a user_data.
+ * @param user_data data to give to @a cb for each element.
+ */
+void
+e_ofono_elements_for_each(Eina_Hash_Foreach cb, const void *user_data)
+{
+   struct e_ofono_elements_for_each_data data = {cb, (void *)user_data};
+
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+
+   eina_hash_foreach
+      (elements, (Eina_Hash_Foreach)_e_ofono_elements_for_each, &data);
+}
+
+static Eina_Bool
+_e_ofono_elements_get_allocate(unsigned int *count, E_Ofono_Element ***p_elements)
+{
+   *count = eina_hash_population(elements);
+   if (*count == 0)
+     {
+        *p_elements = NULL;
+        return EINA_TRUE;
+     }
+
+   *p_elements = malloc(*count * sizeof(E_Ofono_Element *));
+   if (!*p_elements)
+     {
+        ERR("could not allocate return array of %d elements: %s",
+            *count, strerror(errno));
+        *count = 0;
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_ofono_elements_get_all(Eina_Hash *hash __UNUSED__, const char *key __UNUSED__, void *data, void *fdata)
+{
+   E_Ofono_Element *element = data;
+   E_Ofono_Element ***p_ret = fdata;
+
+   **p_ret = element;
+   (*p_ret)++;
+   return EINA_TRUE;
+}
+
+/**
+ * Get all known elements.
+ *
+ * No reference is added to these elements, since there are no threads
+ * in the system, you are free to add references yourself right after
+ * the return of this call without race condition, elements by the
+ * system (ie: elementRemoved signal)could only be touched on the next
+ * main loop iteration.
+ *
+ * @param count return the number of elements in array.
+ * @param p_elements array with all elements, these are not referenced
+ *        and in no particular order, just set if return is 1.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_elements_get_all(unsigned int *count, E_Ofono_Element ***p_elements)
+{
+   E_Ofono_Element **p;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
+
+   if (!_e_ofono_elements_get_allocate(count, p_elements))
+      return EINA_FALSE;
+
+   p = *p_elements;
+   eina_hash_foreach
+      (elements, (Eina_Hash_Foreach)_e_ofono_elements_get_all, &p);
+   return EINA_TRUE;
+}
+
+struct e_ofono_elements_get_all_str_data
+{
+   E_Ofono_Element **elements;
+   int               count;
+   const char       *str;
+};
+
+static Eina_Bool
+_e_ofono_elements_get_all_type(Eina_Hash *hash __UNUSED__, const char *key __UNUSED__, void *e, void *user_data)
+{
+   struct e_ofono_elements_get_all_str_data *data = user_data;
+   E_Ofono_Element *element = e;
+
+   if ((data->str) && (element->interface != data->str))
+      return EINA_TRUE;
+
+   data->elements[data->count] = element;
+   data->count++;
+   return EINA_TRUE;
+}
+
+/**
+ * Get all known elements of type.
+ *
+ * No reference is added to these elements, since there are no threads
+ * in the system, you are free to add references yourself right after
+ * the return of this call without race condition, elements by the
+ * system (ie: ElementRemoved signal) could only be touched on the next
+ * main loop iteration.
+ *
+ * @param type type to filter, or NULL to get all.
+ * @param count return the number of elements in array.
+ * @param p_elements array with all elements, these are not referenced
+ *        and in no particular order, just set if return is 1.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * @see e_ofono_elements_get_all()
+ */
+Eina_Bool
+e_ofono_elements_get_all_type(const char *type, unsigned int *count, E_Ofono_Element ***p_elements)
+{
+   struct e_ofono_elements_get_all_str_data data;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
+
+   if (!_e_ofono_elements_get_allocate(count, p_elements))
+      return EINA_FALSE;
+
+   data.elements = *p_elements;
+   data.count = 0;
+   data.str = eina_stringshare_add(type);
+   eina_hash_foreach(elements,
+                     (Eina_Hash_Foreach)_e_ofono_elements_get_all_type,
+                     &data);
+
+   eina_stringshare_del(data.str);
+   *count = data.count;
+   return EINA_TRUE;
+}
+
+/**
+ * Get the element registered at given path.
+ *
+ * @param path the path to query for registered object.
+ *
+ * @return element pointer if found, NULL otherwise. No references are added.
+ */
+E_Ofono_Element *
+e_ofono_element_get(const char *path, const char *interface)
+{
+   E_Ofono_Element *element;
+   char key[MAX_KEY_SIZE];
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(interface, NULL);
+
+   snprintf(key, MAX_KEY_SIZE, "%s:%s", path, interface);
+   element = eina_hash_find(elements, key);
+
+   return element;
+}
+
+static void
+_e_ofono_element_property_changed_callback(void *data, DBusMessage *msg)
+{
+   E_Ofono_Element *element = (E_Ofono_Element *)data;
+   DBusMessageIter itr, v_itr;
+   int t, r, changed = 0;
+   const char *name = NULL;
+   void *value = NULL;
+
+   DBG("Property changed in element %s %s", element->path, element->interface);
+
+   if (!_dbus_callback_check_and_init(msg, &itr, NULL))
+      return;
+
+   t = dbus_message_iter_get_arg_type(&itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
+     {
+        ERR("missing name in property changed signal");
+        return;
+     }
+
+   dbus_message_iter_get_basic(&itr, &name);
+
+   dbus_message_iter_next(&itr);
+   t = dbus_message_iter_get_arg_type(&itr);
+   if (!_dbus_iter_type_check(t, DBUS_TYPE_VARIANT))
+     {
+        ERR("missing value in property changed signal");
+        return;
+     }
+
+   dbus_message_iter_recurse(&itr, &v_itr);
+   t = dbus_message_iter_get_arg_type(&v_itr);
+
+   if (t == DBUS_TYPE_ARRAY)
+     {
+        value = _e_ofono_element_iter_get_array(&v_itr, name);
+     }
+   else if (t != DBUS_TYPE_INVALID)
+     {
+        dbus_message_iter_get_basic(&v_itr, &value);
+     }
+   else
+     {
+        ERR("property has invalid type %s", name);
+        return;
+     }
+
+   r = _e_ofono_element_property_value_add(element, name, t, value);
+   if (r < 0)
+     {
+        ERR("failed to add property value %s (%c)", name, t);
+     }
+   else if (r == 1)
+     {
+        INF("property value changed %s (%c)", name, t);
+        changed = 1;
+        if ((strcmp(name, "Interfaces") == 0) && value)
+          {
+             char *interface;
+             Eina_Array_Iterator iterator;
+             unsigned int i;
+             E_Ofono_Element *e;
+
+             EINA_ARRAY_ITER_NEXT(((E_Ofono_Array *)value)->array, i,
+                                  interface, iterator)
+             {
+                DBG("Found interface %s on %s", interface, element->path);
+                e_ofono_element_register(element->path, interface);
+                e = e_ofono_element_register(element->path, interface);
+                if ((e) && (!e_ofono_element_properties_sync(e)))
+                   WRN("could not get properties of %s", e->path);
+             }
+          }
+     }
+
+   if (changed)
+      _e_ofono_element_listeners_call(element);
+}
+
+/**
+ * Register the given pair (path, interface), possibly creating an
+ * element and return it.
+ *
+ * This will check if (path, interface) is already registered, in
+ * that case the exiting element is returned. If it was not registered
+ * yet, a new element is created, registered and returned.
+ *
+ * This call will not add extra references to the object.
+ *
+ * @param path the path to register the element
+ *
+ * @return the registered object, no references are added.
+ */
+E_Ofono_Element *
+e_ofono_element_register(const char *path, const char *interface)
+{
+   E_Ofono_Element *element;
+   char key[MAX_KEY_SIZE];
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(interface, NULL);
+
+   snprintf(key, MAX_KEY_SIZE, "%s:%s", path, interface);
+   element = eina_hash_find(elements, key);
+   if (element)
+      return element;
+
+   element = e_ofono_element_new(path, interface);
+   if (!element)
+      return NULL;
+
+   if (!eina_hash_add(elements, key, element))
+     {
+        ERR("could not add element %s to hash, delete it.", path);
+        e_ofono_element_free(element);
+        return NULL;
+     }
+
+   element->signal_handler =
+      e_dbus_signal_handler_add
+         (e_ofono_conn, e_ofono_system_bus_name_get(),
+         element->path, element->interface, "PropertyChanged",
+         _e_ofono_element_property_changed_callback, element);
+
+   e_ofono_element_event_add(E_OFONO_EVENT_ELEMENT_ADD, element);
+
+   return element;
+}
+
+static void
+_e_ofono_element_event_unregister_and_free(void *data __UNUSED__, void *ev)
+{
+   E_Ofono_Element *element = ev;
+   e_ofono_element_unref(element);
+}
+
+static void
+_e_ofono_element_unregister_internal(E_Ofono_Element *element)
+{
+   if (element->signal_handler)
+     {
+        e_dbus_signal_handler_del(e_ofono_conn, element->signal_handler);
+        element->signal_handler = NULL;
+     }
+
+   ecore_event_add(E_OFONO_EVENT_ELEMENT_DEL, element,
+                   _e_ofono_element_event_unregister_and_free, NULL);
+}
+
+/**
+ * Forget about the given element.
+ *
+ * This will remove the element from the pool of known objects, then
+ * add an E_OFONO_EVENT_ELEMENT_DEL and after that will unreference it,
+ * possible freeing it.
+ *
+ * @param element element to forget about. Its reference will be removed.
+ */
+void
+e_ofono_element_unregister(E_Ofono_Element *element)
+{
+   char key[MAX_KEY_SIZE];
+
+   if (!element)
+      return;
+
+   snprintf(key, MAX_KEY_SIZE, "%s:%s", element->path, element->interface);
+   if (elements)
+      eina_hash_del_by_key(elements, key);
+}
+
+/**
+ * Remove all known elements.
+ *
+ * This will remove all known elements but will NOT add any
+ * E_OFONO_EVENT_ELEMENT_DEL to main loop.
+ *
+ * This is just useful to make sure next e_ofono_manager_sync_elements()
+ * will not leave any stale elements. This is unlikely to happen, as
+ * E_Ofono is supposed to catch all required events to avoid stale elements.
+ */
+void
+e_ofono_manager_clear_elements(void)
+{
+   e_ofono_elements_shutdown();
+   e_ofono_elements_init();
+}
+
+/**
+ * Creates elements hash.
+ *
+ * This has no init counter since its already guarded by other code.
+ * @internal
+ */
+void
+e_ofono_elements_init(void)
+{
+   EINA_SAFETY_ON_FALSE_RETURN(!elements);
+   elements =
+      eina_hash_string_superfast_new
+         (EINA_FREE_CB(_e_ofono_element_unregister_internal));
+}
+
+void
+e_ofono_elements_shutdown(void)
+{
+   EINA_SAFETY_ON_FALSE_RETURN(!!elements);
+   eina_hash_free(elements);
+   elements = NULL;
+}
+
+static inline Eina_Bool
+_e_ofono_element_is(const E_Ofono_Element *element, const char *interface)
+{
+   return element->interface == interface;
+}
+
+Eina_Bool
+e_ofono_element_is_manager(const E_Ofono_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return _e_ofono_element_is(element, e_ofono_iface_manager);
+}
+
+Eina_Bool
+e_ofono_element_is_modem(const E_Ofono_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return _e_ofono_element_is(element, e_ofono_iface_modem);
+}
+
+Eina_Bool
+e_ofono_element_is_netreg(const E_Ofono_Element *element)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   return _e_ofono_element_is(element, e_ofono_iface_netreg);
+}
+
diff --git a/src/lib/ofono/e_ofono_manager.c b/src/lib/ofono/e_ofono_manager.c
new file mode 100644 (file)
index 0000000..a35aec1
--- /dev/null
@@ -0,0 +1,45 @@
+#include "e_ofono_private.h"
+
+/**
+ * Get the element manager.
+ *
+ * @return element pointer if found, NULL otherwise.
+ */
+E_Ofono_Element *
+e_ofono_manager_get(void)
+{
+   return e_ofono_element_get(manager_path, e_ofono_iface_manager);
+}
+
+/**
+ * Get array of modem object paths.
+ *
+ * If this property isn't found then 0 is returned.
+ * If zero is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param array where to store the property value, must be a pointer
+ *        to Eina_Array (Eina_Array **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_manager_modems_get(Eina_Array **array)
+{
+   E_Ofono_Element *element;
+   E_Ofono_Array *a = NULL;
+   Eina_Bool r;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(array, EINA_FALSE);
+
+   element = e_ofono_element_get(manager_path, e_ofono_iface_manager);
+   r = e_ofono_element_property_get_stringshared
+         (element, e_ofono_prop_modems, NULL, &a);
+   if (a)
+      *array = a->array;
+
+   return r;
+}
+
diff --git a/src/lib/ofono/e_ofono_modem.c b/src/lib/ofono/e_ofono_modem.c
new file mode 100644 (file)
index 0000000..2bb7041
--- /dev/null
@@ -0,0 +1,68 @@
+#include "e_ofono_private.h"
+
+/* TODO: add a getter for Interfaces property */
+
+/**
+ * Get property "Powered" value.
+ *
+ * @param powered where to store the property value, must be a pointer
+ *        to Eina_Bool (Eina_Bool *), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_modem_powered_get(const E_Ofono_Element *element, Eina_Bool *powered)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(powered, EINA_FALSE);
+
+   return e_ofono_element_property_get_stringshared
+             (element, e_ofono_prop_powered, NULL, powered);
+}
+
+/**
+ * Call method SetProperty("Powered", powered) at the given element on server.
+ *
+ *
+ * @param powered value to set.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_modem_powered_set(E_Ofono_Element *element, Eina_Bool powered, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+
+   return e_ofono_element_property_set_full
+             (element, e_ofono_prop_powered, DBUS_TYPE_BOOLEAN,
+             &powered, cb, data);
+}
+
+/**
+ * Get property "Name" value.
+ *
+ * If this property isn't found then 0 is returned.
+ * If zero is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param address where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_modem_name_get(const E_Ofono_Element *element, const char **name)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
+
+   return e_ofono_element_property_get_stringshared
+             (element, e_ofono_prop_name, NULL, name);
+}
+
diff --git a/src/lib/ofono/e_ofono_network_reg.c b/src/lib/ofono/e_ofono_network_reg.c
new file mode 100644 (file)
index 0000000..34446ee
--- /dev/null
@@ -0,0 +1,94 @@
+#include "e_ofono_private.h"
+
+/**
+ * Get property "Mode" value.
+ *
+ * If this property isn't found then 0 is returned.
+ * If zero is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param mode where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_netreg_mode_get(const E_Ofono_Element *element, const char **mode)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(mode, EINA_FALSE);
+
+   return e_ofono_element_property_get_stringshared
+             (element, e_ofono_prop_mode, NULL, mode);
+}
+
+/**
+ * Get property "Status" value.
+ *
+ * If this property isn't found then 0 is returned.
+ * If zero is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param status where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_netreg_status_get(const E_Ofono_Element *element, const char **status)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(status, EINA_FALSE);
+
+   return e_ofono_element_property_get_stringshared
+             (element, e_ofono_prop_status, NULL, status);
+}
+
+/**
+ * Get property "Operator" value.
+ *
+ * If this property isn't found then 0 is returned.
+ * If zero is returned, then this call failed and parameter-returned
+ * values shall be considered invalid.
+ *
+ * @param operator where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_netreg_operator_get(const E_Ofono_Element *element, const char **op)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(op, EINA_FALSE);
+
+   return e_ofono_element_property_get_stringshared
+             (element, e_ofono_prop_operator, NULL, op);
+}
+
+/**
+ * Get property "Strength" value.
+ *
+ * @param strength where to store the property value, must be a pointer
+ *        to char (char *), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_netreg_strength_get(const E_Ofono_Element *element, uint8_t *strength)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(strength, EINA_FALSE);
+
+   return e_ofono_element_property_get_stringshared
+             (element, e_ofono_prop_strength, NULL, strength);
+}
+
diff --git a/src/lib/ofono/e_ofono_private.h b/src/lib/ofono/e_ofono_private.h
new file mode 100644 (file)
index 0000000..c8b75dc
--- /dev/null
@@ -0,0 +1,125 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *    alloca (size_t);
+#endif
+
+#include <stdio.h>
+
+#include <Eina.h>
+#include <eina_safety_checks.h>
+
+#include "E_Ofono.h"
+
+static const char manager_path[] = "/";
+
+extern const char *e_ofono_iface_manager;
+extern const char *e_ofono_prop_modems;
+extern const char *e_ofono_iface_modem;
+extern const char *e_ofono_prop_name;
+extern const char *e_ofono_prop_powered;
+extern const char *e_ofono_prop_interfaces;
+extern const char *e_ofono_iface_netreg;
+extern const char *e_ofono_prop_mode;
+extern const char *e_ofono_prop_status;
+extern const char *e_ofono_prop_operator;
+extern const char *e_ofono_prop_strength;
+extern const char *e_ofono_iface_sms;
+extern const char *e_ofono_prop_sca;
+extern const char *e_ofono_method_send_sms;
+
+extern int _e_dbus_ofono_log_dom;
+
+#ifndef EINA_LOG_DEFAULT_COLOR
+#define EINA_LOG_DEFAULT_COLOR EINA_COLOR_CYAN
+#endif
+
+#undef DBG
+#undef INF
+#undef WRN
+#undef ERR
+
+#define DBG(...) EINA_LOG_DOM_DBG(_e_dbus_ofono_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_e_dbus_ofono_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_e_dbus_ofono_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_e_dbus_ofono_log_dom, __VA_ARGS__)
+
+typedef struct _E_Ofono_Array   E_Ofono_Array;
+
+struct _E_Ofono_Array
+{
+   int         type;
+   Eina_Array *array;
+};
+
+static inline Eina_Bool
+_dbus_callback_check_and_init(DBusMessage *msg, DBusMessageIter *itr, DBusError *err)
+{
+   if (!msg)
+     {
+        if (err)
+           ERR("an error was reported by server: "
+               "name=\"%s\", message=\"%s\"",
+               err->name, err->message);
+        else
+           ERR("callback without message arguments!");
+
+        return EINA_FALSE;
+     }
+
+   if (!dbus_message_iter_init(msg, itr))
+     {
+        ERR("could not init iterator.");
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static inline Eina_Bool
+__dbus_iter_type_check(int type, int expected, const char *expected_name)
+{
+   if (type == expected)
+      return EINA_TRUE;
+
+   ERR("expected type %s (%c) but got %c instead!",
+       expected_name, expected, type);
+
+   return EINA_FALSE;
+}
+
+#define _dbus_iter_type_check(t, e) __dbus_iter_type_check(t, e, # e)
+
+extern E_DBus_Connection *e_ofono_conn;
+
+const char *         e_ofono_system_bus_name_get(void);
+
+void                 e_ofono_manager_clear_elements(void);
+
+void                 e_ofono_elements_init(void);
+void                 e_ofono_elements_shutdown(void);
+
+E_Ofono_Element *    e_ofono_element_register(const char *path, const char *interface);
+void                 e_ofono_element_unregister(E_Ofono_Element *element);
+
+Eina_Bool            e_ofono_element_message_send(E_Ofono_Element *element, const char *method_name, const char *interface, E_DBus_Method_Return_Cb cb, DBusMessage *msg, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data);
+
+Eina_Bool            e_ofono_element_call_full(E_Ofono_Element *element, const char *method_name, const char *interface, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data);
+Eina_Bool            e_ofono_element_call_with_path(E_Ofono_Element *element, const char *method_name, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data);
+Eina_Bool            e_ofono_element_call_with_string(E_Ofono_Element *element, const char *method_name, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data);
+Eina_Bool            e_ofono_element_call_with_path_and_string(E_Ofono_Element *element, const char *method_name, const char *path, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data);
diff --git a/src/lib/ofono/e_ofono_sms.c b/src/lib/ofono/e_ofono_sms.c
new file mode 100644 (file)
index 0000000..af14281
--- /dev/null
@@ -0,0 +1,78 @@
+#include "e_ofono_private.h"
+
+/**
+ * Get property "ServiceCenterAddress" value.
+ *
+ * @param sca where to store the property value, must be a pointer
+ *        to string (const char **), it will not be allocated or
+ *        copied and references will be valid until element changes,
+ *        so copy it if you want to use it later.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_sms_sca_get(const E_Ofono_Element *element, const char **sca)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(sca, EINA_FALSE);
+
+   return e_ofono_element_property_get_stringshared
+             (element, e_ofono_prop_sca, NULL, sca);
+}
+
+/**
+ * Call method SetProperty("ServiceCenterAddress", powered) at the given
+ * element on server.
+ *
+ *
+ * @param sca value to set.
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_sms_sca_set(E_Ofono_Element *element, const char *sca, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+
+   return e_ofono_element_property_set_full
+             (element, e_ofono_prop_sca, DBUS_TYPE_STRING, sca, cb, data);
+}
+
+/**
+ * Send SMS message.
+ *
+ * Call method SendMessage(number, text) to send a new SMS message.
+ *
+ * @param number the destination of the message
+ * @param message text of message body
+ * @param cb function to call when server replies or some error happens.
+ * @param data data to give to cb when it is called.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+Eina_Bool
+e_ofono_sms_send_message(E_Ofono_Element *element, const char *number, const char *message, E_DBus_Method_Return_Cb cb, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(number, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(message, EINA_FALSE);
+
+   DBusMessage *m;
+   DBusMessageIter i;
+
+   if (!(m = dbus_message_new_method_call(e_ofono_system_bus_name_get(),
+                                          element->path, element->interface,
+                                          e_ofono_method_send_sms)))
+      return EINA_FALSE;
+
+   dbus_message_iter_init_append(m, &i);
+   dbus_message_iter_append_basic(&i, DBUS_TYPE_STRING, &number);
+   dbus_message_iter_append_basic(&i, DBUS_TYPE_STRING, &message);
+
+   return e_ofono_element_message_send(element, e_ofono_method_send_sms,
+                                       e_ofono_iface_sms, NULL, m,
+                                       &element->_pending.send_sms, cb, data);
+}
+
diff --git a/src/lib/ukit/E_Ukit.h b/src/lib/ukit/E_Ukit.h
new file mode 100644 (file)
index 0000000..de86b1d
--- /dev/null
@@ -0,0 +1,169 @@
+#ifndef E_UKIT_H
+#define E_UKIT_H
+
+#include <Eina.h>
+#include <E_DBus.h>
+
+/**
+ * @defgroup EUkit_Group EUkit
+ *
+ * @{
+ */
+
+#define E_UDISKS_BUS "org.freedesktop.UDisks"
+#define E_UDISKS_PATH "/org/freedesktop/UDisks"
+#define E_UDISKS_INTERFACE "org.freedesktop.UDisks.Device"
+
+#define E_UPOWER_BUS "org.freedesktop.UPower"
+#define E_UPOWER_PATH "/org/freedesktop/UPower"
+#define E_UPOWER_INTERFACE "org.freedesktop.UPower.Device"
+
+/* message return types */
+
+typedef struct E_Ukit_Property E_Ukit_Property;
+typedef struct E_Ukit_Properties E_Ukit_Properties;
+
+struct E_Ukit_String_List_Return
+{
+   Eina_List *strings; /* list of const char * */
+};
+
+struct E_Ukit_Bool_Return
+{
+   Eina_Bool boolean;
+};
+
+struct E_Ukit_UDI_Return
+{
+   const char *udi;
+};
+
+struct E_Ukit_Capability
+{
+   const char *udi;
+   const char *capability;
+};
+
+typedef enum
+{
+   E_UKIT_PROPERTY_TYPE_STRING,
+   E_UKIT_PROPERTY_TYPE_INT,
+   E_UKIT_PROPERTY_TYPE_UINT32,
+   E_UKIT_PROPERTY_TYPE_UINT64,
+   E_UKIT_PROPERTY_TYPE_INT64,
+   E_UKIT_PROPERTY_TYPE_BOOL,
+   E_UKIT_PROPERTY_TYPE_DOUBLE,
+   E_UKIT_PROPERTY_TYPE_STRLIST
+} E_Ukit_Property_Type;
+
+struct E_Ukit_Property
+{
+   E_Ukit_Property_Type type;
+   union 
+     {
+        const char *s;
+        int i;
+        Eina_Bool b;
+        double d;
+        uint32_t u;
+        uint64_t t;
+        int64_t x;
+        Eina_List *strlist;
+     } val;
+};
+
+struct E_Ukit_Properties
+{
+   Eina_Hash *properties;
+};
+
+typedef enum
+{
+   E_UPOWER_BATTERY_UNKNOWN,
+   E_UPOWER_BATTERY_LION,
+   E_UPOWER_BATTERY_LPOLYMER,
+   E_UPOWER_BATTERY_LIRONPHOS,
+   E_UPOWER_BATTERY_LEAD,
+   E_UPOWER_BATTERY_NICAD,
+   E_UPOWER_BATTERY_METALHYDRYDE
+} E_UPower_Battery_Type;
+
+typedef enum
+{
+   E_UPOWER_STATE_UNKNOWN,
+   E_UPOWER_STATE_CHARGING,
+   E_UPOWER_STATE_DISCHARGING,
+   E_UPOWER_STATE_EMPTY,
+   E_UPOWER_STATE_FULL,
+   E_UPOWER_STATE_PENDINGCHARGE,
+   E_UPOWER_STATE_PENDINGDISCHARGE
+} E_Upower_State;
+
+typedef enum
+{
+   E_UPOWER_SOURCE_UNKNOWN,
+   E_UPOWER_SOURCE_AC,
+   E_UPOWER_SOURCE_BATTERY,
+   E_UPOWER_SOURCE_UPS,
+   E_UPOWER_SOURCE_MONITOR,
+   E_UPOWER_SOURCE_MOUSE,
+   E_UPOWER_SOURCE_KEYBOARD,
+   E_UPOWER_SOURCE_PDA,
+   E_UPOWER_SOURCE_PHONE
+} E_Upower_Source;
+   
+
+typedef struct E_Ukit_Properties E_Ukit_Get_All_Properties_Return;
+typedef struct E_Ukit_Property E_Ukit_Get_Property_Return;
+typedef struct E_Ukit_String_List_Return E_Ukit_String_List_Return;
+typedef struct E_Ukit_String_List_Return E_Ukit_Get_All_Devices_Return;
+
+typedef struct E_Ukit_UDI_Return E_Ukit_Device_Added;
+typedef struct E_Ukit_UDI_Return E_Ukit_Device_Removed;
+typedef struct E_Ukit_Capability E_Ukit_New_Capability;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+   EAPI int e_ukit_init(void);
+   EAPI int e_ukit_shutdown(void);
+
+   EAPI DBusPendingCall *e_udisks_get_property(E_DBus_Connection *conn, const char *udi, const char *property, E_DBus_Callback_Func cb_func, void *data);
+   EAPI DBusPendingCall *e_udisks_get_all_properties(E_DBus_Connection *conn, const char *udi, E_DBus_Callback_Func cb_func, void *data);
+   EAPI DBusPendingCall *e_udisks_get_all_devices(E_DBus_Connection *conn, E_DBus_Callback_Func cb_func, void *data);
+
+   EAPI DBusPendingCall *e_upower_get_property(E_DBus_Connection *conn, const char *udi, const char *property, E_DBus_Callback_Func cb_func, void *data);
+   EAPI DBusPendingCall *e_upower_get_all_properties(E_DBus_Connection *conn, const char *udi, E_DBus_Callback_Func cb_func, void *data);
+   EAPI DBusPendingCall *e_upower_get_all_devices(E_DBus_Connection *conn, E_DBus_Callback_Func cb_func, void *data);
+
+   EAPI DBusPendingCall * e_upower_suspend_allowed(E_DBus_Connection *conn, E_DBus_Callback_Func cb_func, void *data);
+   EAPI DBusPendingCall * e_upower_suspend(E_DBus_Connection *conn, E_DBus_Callback_Func cb_func, void *data);
+   EAPI DBusPendingCall * e_upower_hibernate(E_DBus_Connection *conn, E_DBus_Callback_Func cb_func, void *data);
+   EAPI DBusPendingCall * e_upower_hibernate_allowed(E_DBus_Connection *conn, E_DBus_Callback_Func cb_func, void *data);
+
+/* utility functions */
+   EAPI void                e_ukit_property_free(E_Ukit_Property *prop);
+   EAPI const char         *e_ukit_property_string_get(E_Ukit_Properties *properties, const char *key, int *err);
+   EAPI Eina_Bool           e_ukit_property_bool_get(E_Ukit_Properties *properties, const char *key, int *err);
+   EAPI int                 e_ukit_property_int_get(E_Ukit_Properties *properties, const char *key, int *err);
+   EAPI uint32_t            e_ukit_property_uint32_get(E_Ukit_Properties *properties, const char *key, int *err);
+   EAPI uint64_t            e_ukit_property_uint64_get(E_Ukit_Properties *properties, const char *key, int *err);
+   EAPI int64_t             e_ukit_property_int64_get(E_Ukit_Properties *properties, const char *key, int *err);
+   EAPI double              e_ukit_property_double_get(E_Ukit_Properties *properties, const char *key, int *err);
+   EAPI const Eina_List    *e_ukit_property_strlist_get(E_Ukit_Properties *properties, const char *key, int *err);
+
+/* (un)mount */
+   EAPI DBusPendingCall *e_udisks_volume_mount(E_DBus_Connection *conn, const char *udi, const char *fstype, Eina_List *options);
+   EAPI DBusPendingCall *e_udisks_volume_unmount(E_DBus_Connection *conn, const char *udi, Eina_List *options);
+   EAPI DBusPendingCall *e_udisks_volume_eject(E_DBus_Connection *conn, const char *udi, Eina_List *options);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/src/lib/ukit/Makefile.am b/src/lib/ukit/Makefile.am
new file mode 100644 (file)
index 0000000..dc32484
--- /dev/null
@@ -0,0 +1,27 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I $(top_srcdir)/src/lib/dbus \
+@EDBUS_CFLAGS@
+
+if BUILD_EUKIT
+
+lib_LTLIBRARIES = libeukit.la
+includes_HEADERS = E_Ukit.h
+includesdir = $(includedir)/e_dbus-@VMAJ@
+
+libeukit_la_SOURCES = \
+e_udisks.c  \
+e_upower.c  \
+e_ukit_util.c \
+e_ukit_main.c \
+e_ukit_private_util.c
+
+libeukit_la_LIBADD = \
+@EDBUS_LIBS@ $(top_builddir)/src/lib/dbus/libedbus.la
+
+libeukit_la_LDFLAGS = -version-info @version_info@ @release_info@
+
+endif
+
+EXTRA_DIST = e_ukit_private.h
diff --git a/src/lib/ukit/e_udisks.c b/src/lib/ukit/e_udisks.c
new file mode 100644 (file)
index 0000000..7a0dd24
--- /dev/null
@@ -0,0 +1,209 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <E_Ukit.h>
+#include "e_ukit_private.h"
+
+#define E_UKIT_BUS E_UDISKS_BUS
+#define E_UKIT_PATH E_UDISKS_PATH
+#define E_UKIT_INTERFACE E_UDISKS_INTERFACE
+
+const char *e_udisks_iface="org.freedesktop.UDisks.Device";
+
+#if 0
+static void cb_device_get_property(void *data, DBusMessage *msg, DBusError *err);
+static void cb_device_get_all_properties(void *data, DBusMessage *msg, DBusError *err);
+static void cb_device_query_capability(void *data, DBusMessage *msg, DBusError *err);
+#endif
+
+/* Properties.Get */
+EAPI DBusPendingCall *
+e_udisks_get_property(E_DBus_Connection *conn, const char *udi, const char *property, E_DBus_Callback_Func cb_func, void *data)
+{
+   DBusMessage *msg;
+   DBusPendingCall *ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(udi, NULL);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(!udi[0], NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(property, NULL);
+
+   msg = e_ukit_property_call_new(udi, "Get");
+   dbus_message_append_args(msg, DBUS_TYPE_STRING, &e_udisks_iface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID);
+   ret = e_dbus_method_call_send(conn, msg, unmarshal_property, cb_func, free_property, -1, data);
+   dbus_message_unref(msg);
+   return ret;
+}
+
+/* Properties.GetAll */
+EAPI DBusPendingCall *
+e_udisks_get_all_properties(E_DBus_Connection *conn, const char *udi, E_DBus_Callback_Func cb_func, void *data)
+{
+   DBusMessage *msg;
+   DBusPendingCall *ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(udi, NULL);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(!udi[0], NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+
+   msg = e_ukit_property_call_new(udi, "GetAll");
+   dbus_message_append_args(msg, DBUS_TYPE_STRING, &e_udisks_iface, DBUS_TYPE_INVALID);
+   ret = e_dbus_method_call_send(conn, msg, unmarshal_device_get_all_properties, cb_func, free_device_get_all_properties, -1, data);
+   dbus_message_unref(msg);
+   return ret;
+}
+
+
+
+/* void FilesystemMount(string fstype, array{string}options) */
+
+/**
+ * @brief Mount a Filesystem
+ *
+ * @param conn the E_DBus_Connection
+ * @param udi the udi of the device object
+ * @param fstype the fstype of the device (e.g. volume.fstype property)
+ * @param options a list of additional options to pass to mount
+ *
+ * @return mount point of fs or error
+ */
+EAPI DBusPendingCall *
+e_udisks_volume_mount(E_DBus_Connection *conn, const char *udi, const char *fstype, Eina_List *options)
+{
+   DBusMessage *msg;
+   DBusMessageIter iter, subiter;
+   Eina_List *l;
+   DBusPendingCall *ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(udi, NULL);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(!udi[0], NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+
+   msg = e_ukit_device_call_new(udi, "FilesystemMount");
+
+   dbus_message_iter_init_append(msg, &iter);
+   dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &fstype);
+   if (dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &subiter))
+     {
+        if (options)
+          {
+             const char *opt;
+             
+             EINA_LIST_FOREACH(options, l, opt)
+               dbus_message_iter_append_basic(&subiter, DBUS_TYPE_STRING, &opt);
+          }
+        dbus_message_iter_close_container(&iter, &subiter);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+
+   ret = e_dbus_method_call_send(conn, msg, NULL, NULL, NULL, -1, NULL);
+   dbus_message_unref(msg);
+   return ret;
+}
+
+/* void Unmount(array{string} options) */
+
+/**
+ * @brief Unmount a Volume
+ *
+ * @param conn the E_DBus_Connection
+ * @param udi the udi of the device object
+ * @param options a list of additional options (currently only 'force' is supported)
+ */
+EAPI DBusPendingCall *
+e_udisks_volume_unmount(E_DBus_Connection *conn, const char *udi, Eina_List *options)
+{
+   DBusMessage *msg;
+   DBusMessageIter iter, subiter;
+   Eina_List *l;
+   DBusPendingCall *ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(udi, NULL);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(!udi[0], NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+
+   msg = e_ukit_device_call_new(udi, "FilesystemUnmount");
+
+   dbus_message_iter_init_append(msg, &iter);
+   if (dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &subiter))
+     {
+        if (options)
+          {
+             const char *opt;
+             
+             EINA_LIST_FOREACH(options, l, opt)
+               dbus_message_iter_append_basic(&subiter, DBUS_TYPE_STRING, &opt);
+          }
+        dbus_message_iter_close_container(&iter, &subiter);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+   
+   ret = e_dbus_method_call_send(conn, msg, NULL, NULL, NULL, -1, NULL);
+   dbus_message_unref(msg);
+   return ret;
+}
+
+/**
+ * @brief Eject a Volume
+ *
+ * @param conn the E_DBus_Connection
+ * @param udi the udi of the device object
+ * @param options a list of additional options (none currently supported)
+ */
+EAPI DBusPendingCall *
+e_udisks_volume_eject(E_DBus_Connection *conn, const char *udi, Eina_List *options)
+{
+   DBusMessage *msg;
+   DBusMessageIter iter, subiter;
+   Eina_List *l;
+   DBusPendingCall *ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(udi, NULL);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(!udi[0], NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+
+   msg = e_ukit_device_call_new(udi, "DriveEject");
+
+   dbus_message_iter_init_append(msg, &iter);
+   if (dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &subiter))
+     {
+        if (options)
+          {
+             const char *opt;
+             
+             EINA_LIST_FOREACH(options, l, opt)
+               dbus_message_iter_append_basic(&subiter, DBUS_TYPE_STRING, &opt);
+          }
+        dbus_message_iter_close_container(&iter, &subiter);
+     }
+   else
+     {
+        ERR("dbus_message_iter_open_container() failed");
+     }
+   
+   ret = e_dbus_method_call_send(conn, msg, NULL, NULL, NULL, -1, NULL);
+   dbus_message_unref(msg);
+   return ret;
+}
+
+/* EnumerateDevices */
+EAPI DBusPendingCall *
+e_udisks_get_all_devices(E_DBus_Connection *conn, E_DBus_Callback_Func cb_func, void *data)
+{
+   DBusMessage *msg;
+   DBusPendingCall *ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+
+   msg = e_ukit_call_new(E_UKIT_PATH, "EnumerateDevices");
+   ret = e_dbus_method_call_send(conn, msg, unmarshal_string_list, cb_func, free_string_list, -1, data);
+   dbus_message_unref(msg);
+   return ret;
+}
diff --git a/src/lib/ukit/e_ukit_main.c b/src/lib/ukit/e_ukit_main.c
new file mode 100644 (file)
index 0000000..c541e3d
--- /dev/null
@@ -0,0 +1,58 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <E_Ukit.h>
+#include "e_ukit_private.h"
+
+int _e_dbus_ukit_log_dom = -1;
+int _e_dbus_ukit_init_count = 0;
+
+EAPI int
+e_ukit_init(void)
+{
+   if (++_e_dbus_ukit_init_count != 1)
+     return _e_dbus_ukit_init_count;
+
+   if (!eina_init())
+     return --_e_dbus_ukit_init_count;
+
+   _e_dbus_ukit_log_dom = eina_log_domain_register
+     ("e_ukit", E_DBUS_COLOR_DEFAULT);
+   if (_e_dbus_ukit_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register 'e_ukit' log domain.");
+        goto shutdown_eina;
+     }
+
+   if (!e_dbus_init())
+     {
+        ERR("Could not initialize E_DBus.");
+        goto unregister_log_domain;
+     }
+
+   return _e_dbus_ukit_init_count;
+
+   unregister_log_domain:
+     eina_log_domain_unregister(_e_dbus_ukit_log_dom);
+     _e_dbus_ukit_log_dom = -1;
+   shutdown_eina:
+     eina_shutdown();
+
+   return _e_dbus_ukit_init_count;
+}
+
+EAPI int
+e_ukit_shutdown(void)
+{
+   if (--_e_dbus_ukit_init_count != 0)
+     return _e_dbus_ukit_init_count;
+
+   e_dbus_shutdown();
+
+   eina_log_domain_unregister(_e_dbus_ukit_log_dom);
+   _e_dbus_ukit_log_dom = -1;
+   eina_shutdown();
+
+   return _e_dbus_ukit_init_count;
+}
diff --git a/src/lib/ukit/e_ukit_private.h b/src/lib/ukit/e_ukit_private.h
new file mode 100644 (file)
index 0000000..c25ee67
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef E_UKIT_PRIVATE_H
+#define E_UKIT_PRIVATE_H
+
+#ifndef E_DBUS_COLOR_DEFAULT
+# define E_DBUS_COLOR_DEFAULT EINA_COLOR_CYAN
+#endif
+
+extern int _e_dbus_ukit_log_dom;
+
+#ifdef ERR
+# undef ERR
+#endif
+
+#ifdef INF
+# undef INF
+#endif
+
+#ifdef WARN
+# undef WARN
+#endif
+
+#ifdef DBG
+# undef DBG
+#endif
+
+#define e_ukit_call_new(udi, member) dbus_message_new_method_call(E_UKIT_BUS, udi, E_UKIT_BUS, member)
+#define e_ukit_device_call_new(udi, member) dbus_message_new_method_call(E_UKIT_BUS, udi, E_UKIT_INTERFACE, member)
+#define e_ukit_property_call_new(udi, member) dbus_message_new_method_call(E_UKIT_BUS, udi, E_DBUS_FDO_INTERFACE_PROPERTIES, member)
+
+#define DBG(...)   EINA_LOG_DOM_DBG(_e_dbus_ukit_log_dom, __VA_ARGS__)
+#define INFO(...)    EINA_LOG_DOM_INFO(_e_dbus_ukit_log_dom, __VA_ARGS__)
+#define WARN(...) EINA_LOG_DOM_WARN(_e_dbus_ukit_log_dom, __VA_ARGS__)
+#define ERR(...)   EINA_LOG_DOM_ERR(_e_dbus_ukit_log_dom, __VA_ARGS__)
+
+void *unmarshal_property(DBusMessage *msg, DBusError *err);
+void  free_property(void *data);
+void *unmarshal_device_get_all_properties(DBusMessage *msg, DBusError *err);
+void  free_device_get_all_properties(void *data);
+void *unmarshal_string_list(DBusMessage *msg, DBusError *err);
+void  free_string_list(void *data);
+
+
+#endif
diff --git a/src/lib/ukit/e_ukit_private_util.c b/src/lib/ukit/e_ukit_private_util.c
new file mode 100644 (file)
index 0000000..f024079
--- /dev/null
@@ -0,0 +1,259 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include <E_Ukit.h>
+#include "e_ukit_private.h"
+
+void *
+unmarshal_property(DBusMessage *msg, DBusError *err)
+{
+   E_Ukit_Get_Property_Return *ret = NULL;
+   DBusMessageIter iter, a_iter;
+   int type;
+   char *tmp;
+
+   if (!dbus_message_iter_init(msg, &iter)) return NULL; /* no params in message */
+
+   ret = calloc(1, sizeof(E_Ukit_Get_Property_Return));
+   if (!ret) 
+     {
+        dbus_set_error(err, DBUS_ERROR_NO_MEMORY, "");
+        return NULL;
+     }
+
+   dbus_message_iter_recurse(&iter, &a_iter);
+   if (dbus_message_iter_get_arg_type(&a_iter) != DBUS_TYPE_INVALID)
+     {
+        type = dbus_message_iter_get_arg_type(&a_iter);    
+
+        switch(type)
+          {
+             case DBUS_TYPE_STRING:
+             case DBUS_TYPE_OBJECT_PATH:
+               ret->type = E_UKIT_PROPERTY_TYPE_STRING;
+               dbus_message_iter_get_basic(&a_iter, &tmp);
+               ret->val.s = eina_stringshare_add(tmp);
+               break;
+             case DBUS_TYPE_INT32:
+               ret->type = E_UKIT_PROPERTY_TYPE_INT;
+               dbus_message_iter_get_basic(&a_iter, &(ret->val.i));
+               break;
+             case DBUS_TYPE_UINT32:
+               ret->type = E_UKIT_PROPERTY_TYPE_UINT32;
+               dbus_message_iter_get_basic(&a_iter, &(ret->val.u));
+               break;
+             case DBUS_TYPE_UINT64:
+               ret->type = E_UKIT_PROPERTY_TYPE_UINT64;
+               dbus_message_iter_get_basic(&a_iter, &(ret->val.t));
+               break;
+             case DBUS_TYPE_INT64:
+               ret->type = E_UKIT_PROPERTY_TYPE_INT64;
+               dbus_message_iter_get_basic(&a_iter, &(ret->val.x));
+               break;
+             case DBUS_TYPE_BOOLEAN:
+               ret->type = E_UKIT_PROPERTY_TYPE_BOOL;
+               dbus_message_iter_get_basic(&a_iter, &(ret->val.b));
+               break;
+             case DBUS_TYPE_DOUBLE:
+               ret->type = E_UKIT_PROPERTY_TYPE_DOUBLE;
+               dbus_message_iter_get_basic(&a_iter, &(ret->val.d));
+               break;
+             case DBUS_TYPE_ARRAY:
+               ret->type = E_UKIT_PROPERTY_TYPE_STRLIST;
+               {
+                  DBusMessageIter list_iter;
+                  ret->val.strlist = NULL;
+                  dbus_message_iter_recurse(&a_iter, &list_iter);
+                  while (dbus_message_iter_get_arg_type(&list_iter) != DBUS_TYPE_INVALID)
+                    {
+                       char *str;
+                       dbus_message_iter_get_basic(&list_iter, &str);
+                       tmp = (char*)eina_stringshare_add(str);
+                       ret->val.strlist = eina_list_append(ret->val.strlist, tmp);
+                       dbus_message_iter_next(&list_iter);
+                    }
+                }
+                break;
+             default:
+               break;
+          }
+     }
+
+   return ret;
+}
+
+void 
+free_property(void *data)
+{
+   E_Ukit_Get_Property_Return *ret = data;
+
+   if (!ret) return;
+   if (ret->type == E_UKIT_PROPERTY_TYPE_STRLIST)
+     {
+        const char *s;
+        EINA_LIST_FREE(ret->val.strlist, s)
+          eina_stringshare_del(s);
+     }
+   else if (ret->type == E_UKIT_PROPERTY_TYPE_STRING)
+     eina_stringshare_del(ret->val.s);
+   free(ret);
+}
+
+void *
+unmarshal_device_get_all_properties(DBusMessage *msg, DBusError *err)
+{
+   E_Ukit_Get_All_Properties_Return *ret = NULL;
+   DBusMessageIter iter, a_iter, s_iter, v_iter;
+   int type;
+   char *tmp;
+
+   /* a{sv} = array of string+variants */
+   if (!dbus_message_has_signature(msg, "a{sv}")) 
+     {
+        dbus_set_error(err, DBUS_ERROR_INVALID_SIGNATURE, "");
+        return NULL;
+     }
+
+   ret = calloc(1, sizeof(E_Ukit_Get_All_Properties_Return));
+   if (!ret) 
+     {
+         dbus_set_error(err, DBUS_ERROR_NO_MEMORY, "");
+         return NULL;
+     }
+
+   ret->properties = eina_hash_string_small_new(EINA_FREE_CB(e_ukit_property_free));
+
+   dbus_message_iter_init(msg, &iter);
+   dbus_message_iter_recurse(&iter, &a_iter);
+   while (dbus_message_iter_get_arg_type(&a_iter) != DBUS_TYPE_INVALID)
+   {
+      const char *name;
+      E_Ukit_Property *prop = calloc(1, sizeof(E_Ukit_Property));
+      dbus_message_iter_recurse(&a_iter, &s_iter);
+      dbus_message_iter_get_basic(&s_iter, &name);
+      dbus_message_iter_next(&s_iter);
+      dbus_message_iter_recurse(&s_iter, &v_iter);
+      
+      type = dbus_message_iter_get_arg_type(&v_iter);
+      switch(type)
+        {
+           case DBUS_TYPE_STRING:
+           case DBUS_TYPE_OBJECT_PATH:
+             prop->type = E_UKIT_PROPERTY_TYPE_STRING;
+             dbus_message_iter_get_basic(&v_iter, &tmp);
+             prop->val.s = eina_stringshare_add(tmp);
+             break;
+           case DBUS_TYPE_INT32:
+             prop->type = E_UKIT_PROPERTY_TYPE_INT;
+             dbus_message_iter_get_basic(&v_iter, &(prop->val.i));
+             break;
+           case DBUS_TYPE_UINT32:
+             prop->type = E_UKIT_PROPERTY_TYPE_UINT32;
+             dbus_message_iter_get_basic(&v_iter, &(prop->val.u));
+             break;
+           case DBUS_TYPE_UINT64:
+             prop->type = E_UKIT_PROPERTY_TYPE_UINT64;
+             dbus_message_iter_get_basic(&v_iter, &(prop->val.t));
+             break;
+           case DBUS_TYPE_INT64:
+             prop->type = E_UKIT_PROPERTY_TYPE_INT64;
+             dbus_message_iter_get_basic(&v_iter, &(prop->val.x));
+             break;
+           case DBUS_TYPE_BOOLEAN:
+             prop->type = E_UKIT_PROPERTY_TYPE_BOOL;
+             dbus_message_iter_get_basic(&v_iter, &(prop->val.b));
+             break;
+           case DBUS_TYPE_DOUBLE:
+             prop->type = E_UKIT_PROPERTY_TYPE_DOUBLE;
+             dbus_message_iter_get_basic(&v_iter, &(prop->val.d));
+             break;
+           case DBUS_TYPE_ARRAY:
+             prop->type = E_UKIT_PROPERTY_TYPE_STRLIST;
+             {
+                DBusMessageIter list_iter;
+                prop->val.strlist = NULL;
+                dbus_message_iter_recurse(&v_iter, &list_iter);
+                while (dbus_message_iter_get_arg_type(&list_iter) != DBUS_TYPE_INVALID)
+                {
+                   char *str;
+                   dbus_message_iter_get_basic(&list_iter, &str);
+                   tmp = (char*)eina_stringshare_add(str);
+                   prop->val.strlist = eina_list_append(prop->val.strlist, tmp);
+                   dbus_message_iter_next(&list_iter);
+                }
+             }
+             break;
+           default:
+             WARN("EUkit Error: unexpected property type (%s): %c", name, dbus_message_iter_get_arg_type(&v_iter));
+             break;
+        }
+      eina_hash_add(ret->properties, name, prop);
+
+      dbus_message_iter_next(&a_iter);
+   }
+
+   return ret;
+}
+
+void
+free_device_get_all_properties(void *data)
+{
+   E_Ukit_Get_All_Properties_Return *ret = data;
+
+   if (!ret) return;
+   eina_hash_free(ret->properties);
+   free(ret);
+}
+
+void *
+unmarshal_string_list(DBusMessage *msg, DBusError *err)
+{
+   E_Ukit_String_List_Return *ret = NULL;
+   DBusMessageIter iter, sub;
+   char *tmp;
+
+   /* ao = array of object strings */
+   if (!dbus_message_has_signature(msg, "ao")) 
+     {
+        dbus_set_error(err, DBUS_ERROR_INVALID_SIGNATURE, "");
+        return NULL;
+     }
+
+   ret = calloc(1, sizeof(E_Ukit_String_List_Return));
+   if (!ret) 
+     {
+        dbus_set_error(err, DBUS_ERROR_NO_MEMORY, "");
+        return NULL;
+     }
+
+   ret->strings = NULL;
+
+   dbus_message_iter_init(msg, &iter);
+   dbus_message_iter_recurse(&iter, &sub);
+   while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID)
+     {
+        char *dev = NULL;
+
+        dbus_message_iter_get_basic(&sub, &dev);
+        tmp = (char*)eina_stringshare_add(dev);
+        if (dev) ret->strings = eina_list_append(ret->strings, tmp);
+        dbus_message_iter_next(&sub);
+     }
+
+   return ret;
+}
+
+void
+free_string_list(void *data)
+{
+   E_Ukit_String_List_Return *ret = data;
+   const char *x;
+
+   if (!ret) return;
+   EINA_LIST_FREE(ret->strings, x)
+     eina_stringshare_del(x);
+   free(ret);
+}
diff --git a/src/lib/ukit/e_ukit_util.c b/src/lib/ukit/e_ukit_util.c
new file mode 100644 (file)
index 0000000..cb97154
--- /dev/null
@@ -0,0 +1,129 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <E_Ukit.h>
+#include "e_ukit_private.h"
+
+/**
+ * @internal
+ * @brief free a property structure
+ * @param prop the property to free
+ */
+EAPI void
+e_ukit_property_free(E_Ukit_Property *prop)
+{
+   if (prop->type == E_UKIT_PROPERTY_TYPE_STRLIST)
+     eina_list_free(prop->val.strlist);
+   free(prop);
+}
+
+/**
+ * @brief Retrive a string from an element of a property hash
+ * @param properties the E_Ukit_Properties structure
+ * @param key the key of the property to retrieve
+ * @param err a pointer to an int, which if supplied, will be set to 0 on success and 1 on an error
+ */
+EAPI const char *
+e_ukit_property_string_get(E_Ukit_Properties *properties, const char *key, int *err)
+{
+   E_Ukit_Property *prop;
+   if (err) *err = 0;
+   if (!properties->properties) return NULL;
+   prop = eina_hash_find(properties->properties, key);
+   if (prop) return prop->val.s;
+
+   if (err) *err = 1;
+   return NULL;
+}
+
+EAPI Eina_Bool
+e_ukit_property_bool_get(E_Ukit_Properties *properties, const char *key, int *err)
+{
+   E_Ukit_Property *prop;
+   if (err) *err = 0;
+   if (!properties->properties) return EINA_FALSE;
+   prop = eina_hash_find(properties->properties, key);
+   if (prop) return prop->val.b;
+   
+   if (err) *err = 1;
+   return EINA_FALSE;
+}
+
+EAPI int
+e_ukit_property_int_get(E_Ukit_Properties *properties, const char *key, int *err)
+{
+   E_Ukit_Property *prop;
+   if (err) *err = 0;
+   if (!properties->properties) return 0;
+   prop = eina_hash_find(properties->properties, key);
+   if (prop) return prop->val.i;
+
+   if (err) *err = 1;
+   return 0;
+}
+
+EAPI uint32_t
+e_ukit_property_uint32_get(E_Ukit_Properties *properties, const char *key, int *err)
+{
+   E_Ukit_Property *prop;
+   if (err) *err = 0;
+   if (!properties->properties) return 0;
+   prop = eina_hash_find(properties->properties, key);
+   if (prop) return prop->val.u;
+
+   if (err) *err = 1;
+   return 0;
+}
+
+EAPI uint64_t
+e_ukit_property_uint64_get(E_Ukit_Properties *properties, const char *key, int *err)
+{
+   E_Ukit_Property *prop;
+   if (err) *err = 0;
+   if (!properties->properties) return 0;
+   prop = eina_hash_find(properties->properties, key);
+   if (prop) return prop->val.t;
+
+   if (err) *err = 1;
+   return 0;
+}
+
+EAPI int64_t
+e_ukit_property_int64_get(E_Ukit_Properties *properties, const char *key, int *err)
+{
+   E_Ukit_Property *prop;
+   if (err) *err = 0;
+   if (!properties->properties) return 0;
+   prop = eina_hash_find(properties->properties, key);
+   if (prop) return prop->val.x;
+
+   if (err) *err = 1;
+   return 0;
+}
+
+EAPI double
+e_ukit_property_double_get(E_Ukit_Properties *properties, const char *key, int *err)
+{
+   E_Ukit_Property *prop;
+   if (err) *err = 0;
+   if (!properties->properties) return 0;
+   prop = eina_hash_find(properties->properties, key);
+   if (prop) return prop->val.d;
+
+   if (err) *err = 1;
+   return 0;
+}
+
+EAPI const Eina_List *
+e_ukit_property_strlist_get(E_Ukit_Properties *properties, const char *key, int *err)
+{
+   E_Ukit_Property *prop;
+   if (err) *err = 0;
+   if (!properties->properties) return NULL;
+   prop = eina_hash_find(properties->properties, key);
+   if (prop) return prop->val.strlist;
+
+   if (err) *err = 1;
+   return NULL;
+}
diff --git a/src/lib/ukit/e_upower.c b/src/lib/ukit/e_upower.c
new file mode 100644 (file)
index 0000000..f3bc6e5
--- /dev/null
@@ -0,0 +1,131 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <E_Ukit.h>
+#include "e_ukit_private.h"
+
+#define E_UKIT_BUS E_UPOWER_BUS
+#define E_UKIT_PATH E_UPOWER_PATH
+#define E_UKIT_INTERFACE E_UPOWER_INTERFACE
+
+const char *e_upower_iface="org.freedesktop.UPower.Device";
+
+#if 0
+static void cb_device_get_property(void *data, DBusMessage *msg, DBusError *err);
+static void cb_device_get_all_properties(void *data, DBusMessage *msg, DBusError *err);
+static void cb_device_query_capability(void *data, DBusMessage *msg, DBusError *err);
+#endif
+
+/* Properties.Get */
+EAPI DBusPendingCall *
+e_upower_get_property(E_DBus_Connection *conn, const char *udi, const char *property, E_DBus_Callback_Func cb_func, void *data)
+{
+   DBusMessage *msg;
+   DBusPendingCall *ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(udi, NULL);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(!udi[0], NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(property, NULL);
+
+   msg = e_ukit_property_call_new(udi, "Get");
+   dbus_message_append_args(msg, DBUS_TYPE_STRING, &e_upower_iface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID);
+   ret = e_dbus_method_call_send(conn, msg, unmarshal_property, cb_func, free_property, -1, data);
+   dbus_message_unref(msg);
+   return ret;
+}
+
+/* Properties.GetAll */
+EAPI DBusPendingCall *
+e_upower_get_all_properties(E_DBus_Connection *conn, const char *udi, E_DBus_Callback_Func cb_func, void *data)
+{
+   DBusMessage *msg;
+   DBusPendingCall *ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(udi, NULL);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(!udi[0], NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+
+   msg = e_ukit_property_call_new(udi, "GetAll");
+   dbus_message_append_args(msg, DBUS_TYPE_STRING, &e_upower_iface, DBUS_TYPE_INVALID);
+   ret = e_dbus_method_call_send(conn, msg, unmarshal_device_get_all_properties, cb_func, free_device_get_all_properties, -1, data);
+   dbus_message_unref(msg);
+   return ret;
+}
+
+
+EAPI DBusPendingCall *
+e_upower_hibernate(E_DBus_Connection *conn, E_DBus_Callback_Func cb_func, void *data)
+{
+   DBusMessage *msg;
+   DBusPendingCall *ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+
+   msg = e_ukit_call_new(E_UKIT_PATH, "Hibernate");
+
+   ret = e_dbus_method_call_send(conn, msg, NULL, cb_func, NULL, -1, data);
+   dbus_message_unref(msg);
+   return ret;
+}
+
+EAPI DBusPendingCall *
+e_upower_suspend(E_DBus_Connection *conn, E_DBus_Callback_Func cb_func, void *data)
+{
+   DBusMessage *msg;
+   DBusPendingCall *ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+
+   msg = e_ukit_call_new(E_UKIT_PATH, "Suspend");
+
+   ret = e_dbus_method_call_send(conn, msg, NULL, cb_func, NULL, -1, data);
+   dbus_message_unref(msg);
+   return ret;
+}
+
+EAPI DBusPendingCall *
+e_upower_hibernate_allowed(E_DBus_Connection *conn, E_DBus_Callback_Func cb_func, void *data)
+{
+   DBusMessage *msg;
+   DBusPendingCall *ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+
+   msg = e_ukit_call_new(E_UKIT_PATH, "HibernateAllowed");
+
+   ret = e_dbus_method_call_send(conn, msg, unmarshal_property, cb_func, free_property, -1, data);
+   dbus_message_unref(msg);
+   return ret;
+}
+
+EAPI DBusPendingCall *
+e_upower_suspend_allowed(E_DBus_Connection *conn, E_DBus_Callback_Func cb_func, void *data)
+{
+   DBusMessage *msg;
+   DBusPendingCall *ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+   
+   msg = e_ukit_call_new(E_UKIT_PATH, "SuspendAllowed");
+
+   ret = e_dbus_method_call_send(conn, msg, unmarshal_property, cb_func, free_property, -1, data);
+   dbus_message_unref(msg);
+   return ret;
+}
+
+/* EnumerateDevices */
+EAPI DBusPendingCall *
+e_upower_get_all_devices(E_DBus_Connection *conn, E_DBus_Callback_Func cb_func, void *data)
+{
+   DBusMessage *msg;
+   DBusPendingCall *ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+
+   msg = e_ukit_call_new(E_UKIT_PATH, "EnumerateDevices");
+   ret = e_dbus_method_call_send(conn, msg, unmarshal_string_list, cb_func, free_string_list, -1, data);
+   dbus_message_unref(msg);
+   return ret;
+}