--- /dev/null
+*.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
+config.guess.cdbs-orig
+config.sub.cdbs-orig
+debian/files
+debian/*.log
+debian/*.substvars
+debian/*.debhelper
+debian/stamp-*
+debian/libedbus-dbg/
+debian/libedbus-dev/
+debian/libedbus/
+debian/tmp/
--- /dev/null
+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>
--- /dev/null
+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.
--- /dev/null
+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
+
+2012-08-30 Carsten Haitzler (The Rasterman)
+
+ 1.7.0 release
+
+2012-09-12 Mike Blumenkrantz
+
+ * e_dbus_signal_handler_add() no longer blocks
--- /dev/null
+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.
+
--- /dev/null
+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
--- /dev/null
+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.
--- /dev/null
+E_dbus 1.7.99
+
+******************************************************************************
+
+ 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
+
--- /dev/null
+#!/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
--- /dev/null
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+m4_define([v_maj], [1])
+m4_define([v_min], [7])
+m4_define([v_mic], [99])
+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
+dnl 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
--- /dev/null
+edbus (1.2.0+svn.70375slp2+build02) unstable; urgency=low
+
+ * Package Upload
+ * Git: slp/pkgs/e/edbus
+ * Tag: edbus_1.2.0+svn.70375slp2+build02
+
+ -- Myungjae Lee <mjae.lee@samsung.com> Wed, 25 Apr 2012 17:28:54 +0900
+
+edbus (1.2.0+svn.70375slp2+build01) unstable; urgency=low
+
+ * Package Upload
+ * Git: slp/pkgs/e/edbus
+ * Tag: edbus_1.2.0+svn.70375slp2+build01
+
+ -- Myungjae Lee <mjae.lee@samsung.com> Wed, 25 Apr 2012 15:14:28 +0900
+
+edbus (1.2.0+svn.70217slp2+build01) unstable; urgency=low
+
+ * Package Upload
+ * Git: slp/pkgs/e/edbus
+ * Tag: edbus_1.2.0+svn.70217slp2+build01
+
+ -- Hyoyoung Chang <hyoyoung.chang@samsung.com> Wed, 18 Apr 2012 18:12:12 +0900
+
+edbus (1.2.0+svn.69484slp2+build01) unstable; urgency=low
+
+ * Package Upload
+ * Git: slp/pkgs/e/edbus
+ * Tag: edbus_1.2.0+svn.69484slp2+build01
+
+ -- Jeonghyun Yun <jh0506.yun@samsung.com> Fri, 06 Apr 2012 18:29:53 +0900
+
+edbus (1.0.0.001+svn.69484slp2+build01) unstable; urgency=low
+
+ * Package Upload
+ * Git: slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.69484slp2+build01
+
+ -- Jeonghyun Yun <jh0506.yun@samsung.com> Wed, 28 Mar 2012 14:30:12 +0900
+
+edbus (1.0.0.001+svn.69376slp2+build02) unstable; urgency=low
+
+ * Package Upload
+ * Git: slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.69376slp2+build02
+
+ -- Jeonghyun Yun <jh0506.yun@samsung.com> Sun, 18 Mar 2012 14:02:40 +0900
+
+edbus (1.0.0.001+svn.69376slp2+build01) unstable; urgency=low
+
+ * EFL migration
+ * Git: slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.69376slp2+build01
+
+ -- Jeonghyun Yun <jh0506.yun@samsung.com> Fri, 16 Mar 2012 21:51:11 +0900
+
+edbus (1.0.0.001+svn.69045slp2+build01) unstable; urgency=low
+
+ * Package Upload
+ * Git: slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.69045slp2+build01
+
+ -- Jeonghyun Yun <jh0506.yun@samsung.com> Sat, 10 Mar 2012 13:51:27 +0900
+
+edbus (1.0.0.001+svn.68464slp2+build02) unstable; urgency=low
+
+ * 69045
+ * Git: slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.68464slp2+build02
+
+ -- Jeonghyun Yun <jh0506.yun@samsung.com> Sat, 10 Mar 2012 13:21:37 +0900
+
+edbus (1.0.0.001+svn.68464slp2+build01) unstable; urgency=low
+
+ * Package Upload
+ * Git: slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.68464slp2+build01
+
+ -- Jeonghyun Yun <jh0506.yun@samsung.com> Fri, 02 Mar 2012 06:33:54 -0500
+
+edbus (1.0.0.001+svn.67284slp2+build01) unstable; urgency=low
+
+ * Package Upload
+ * Git: slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.67284slp2+build01
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Wed, 15 Feb 2012 19:02:20 +0900
+
+edbus (1.0.0.001+svn.66792slp2+build01) unstable; urgency=low
+
+ * Package Upload
+ * Git: slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.66792slp2+build01
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Mon, 16 Jan 2012 18:37:25 +0900
+
+edbus (1.0.0.001+svn.65860slp2+build01) unstable; urgency=low
+
+ * Package Upload for migration
+ * Git: slp-scm.sec.samsung.net:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.65860slp2+build01
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Thu, 08 Dec 2011 13:54:59 +0900
+
+edbus (1.0.0.001+svn.65617slp2+build01) unstable; urgency=low
+
+ * Package Upload
+ * Git: slp-scm.sec.samsung.net:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.65617slp2+build01
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Tue, 29 Nov 2011 14:13:40 +0900
+
+edbus (1.0.0.001+svn.65213slp2+build01) unstable; urgency=low
+
+ * Merge with upstream @65213
+
+ -- Mike McCormack <mj.mccormack@samsung.com> Tue, 15 Nov 2011 18:02:54 +0900
+
+edbus (1.0.0.001+svn.62640slp2+build01) unstable; urgency=low
+
+ * [SVN EFL Migration] e_dbus in SLP is merged with SVN r62640
+ * Important Changes
+ [Migration upstream r62640] Merge branch 'svn_merge'
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.62640slp2+build01
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Fri, 02 Sep 2011 18:45:36 +0900
+
+edbus (1.0.0.001+svn.60291slp2+build01) unstable; urgency=low
+
+ * [SVN EFL Migration] e_dbus in SLP is merged with SVN r60291
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.60291slp2+build01
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Fri, 24 Jun 2011 18:10:30 +0900
+
+edbus (1.0.0.001+svn.58123slp2+build01) unstable; urgency=low
+
+ * [SVN EFL Migration] e_dbus in SLP is merged with SVN r58123
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.58123slp2+build01
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Tue, 05 Apr 2011 15:55:28 +0900
+
+edbus (1.0.0.001+svn.57317slp2+build07) unstable; urgency=low
+
+ * [SVN EFL Migration] e_dbus in SLP is merged with SVN r57317
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.57317slp2+build07
+
+ -- Shinwoo Kim <cinoo.kim@samsung.com> Tue, 29 Mar 2011 18:55:53 +0900
+
+edbus (1.0.0.001+svn.57317slp2+build06) unstable; urgency=low
+
+ * [SVN EFL Migration] e_dbus in SLP is merged with SVN r57317
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.57317slp2+build06
+
+ -- Myungjae Lee <mjae.lee@samsung.com> Wed, 09 Mar 2011 11:30:04 +0900
+
+edbus (1.0.0.001+svn.57317slp2+build05) unstable; urgency=low
+
+ * [SVN EFL Migration] e_dbus in SLP is merged with SVN r57317
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.57317slp2+build05
+
+ -- Myungjae Lee <mjae.lee@samsung.com> Wed, 09 Mar 2011 11:15:18 +0900
+
+edbus (1.0.0.001+svn.57317slp2+build04) unstable; urgency=low
+
+ * Package Upload : Rollback
+ * Git: 165.213.180.234:/slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.57317slp2+build04
+
+ -- WooHyun Jung <wh0705.jung@samsung.com> Tue, 08 Mar 2011 14:08:56 +0900
+
+edbus (1.0.0.001+svn.57317slp2+build03) unstable; urgency=low
+
+ * Package Upload : Rollback
+ * Git: 165.213.180.234:/slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.57317slp2+build03
+
+ -- WooHyun Jung <wh0705.jung@samsung.com> Tue, 08 Mar 2011 12:49:38 +0900
+
+edbus (1.0.0.001+svn.57317slp2+build02) unstable; urgency=low
+
+ * Package Upload : rollback
+ * Git: 165.213.180.234:/slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.57317slp2+build02
+
+ -- WooHyun Jung <wh0705.jung@samsung.com> Tue, 08 Mar 2011 11:15:03 +0900
+
+edbus (1.0.0.001+svn.57317slp2+build01) unstable; urgency=low
+
+ * [SVN EFL Migration] e_dbus in SLP is merged with SVN r57317
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.57317slp2+build01
+
+ -- Myungjae Lee <mjae.lee@samsung.com> Mon, 07 Mar 2011 17:28:32 +0900
+
+edbus (1.0.0.001+svn.56223slp2+build01) unstable; urgency=low
+
+ * [SVN EFL Migration] e_dbus in SLP is merged with SVN r56223
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.56223slp2+build01
+
+ -- WooHyun Jung <wh0705.jung@samsung.com> Thu, 27 Jan 2011 12:24:08 +0900
+
+edbus (1.0.0.001+svn.55948slp2+build01) unstable; urgency=low
+
+ * [SVN EFL Migration] e_dbus in SLP is merged with SVN r55948
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.55948slp2+build01
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.55948slp2+build01
+
+ -- WooHyun Jung <wh0705.jung@samsung.com> Wed, 19 Jan 2011 16:21:14 +0900
+
+edbus (1.0.0.001+svn.55737slp2+build01) unstable; urgency=low
+
+ * [SVN EFL Migration] e_dbus in SLP is merged with SVN r55737
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.55737slp2+build01
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Mon, 03 Jan 2011 21:23:09 +0900
+
+edbus (1.0.0.001+svn.55503slp2+build02) unstable; urgency=low
+
+ * [src/bin/Makefile.am] Fixed build error in sbs.
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.55503slp2+build02
+
+ -- Juyung Seo <juyung.seo@samsung.com> Thu, 23 Dec 2010 09:49:14 +0900
+
+edbus (1.0.0.001+svn.55503slp2+build01) unstable; urgency=low
+
+ * [SVN EFL Migration] edbus in SLP is merged with SVN r55503
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.55503slp2+build01
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Wed, 22 Dec 2010 20:11:01 +0900
+
+edbus (1.0.0.001+svn.55238slp2+build02) unstable; urgency=low
+
+ * [src/bin/Makefile.am] Applied Rafal's patch.
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.55238slp2+build02
+
+ -- Juyung Seo <juyung.seo@samsung.com> Wed, 15 Dec 2010 09:35:27 +0900
+
+edbus (1.0.0.001+svn.55238slp2+build01) unstable; urgency=low
+
+ * [SVN's EFL Migration] e-dbus in SLP is merged with SVN r55238.
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.55238slp2+build01
+
+ -- Juyung Seo <juyung.seo@samsung.com> Tue, 14 Dec 2010 17:52:10 +0900
+
+edbus (1.0.0.001+svn.55010slp2+build03) unstable; urgency=low
+
+ * [SVN's EFL Migration] e-dbus in SLP is merged with SVN r55238.
+ * Git: 165.213.180.234:slp/pkgs/e/edbus
+ * Tag: edbus_1.0.0.001+svn.55010slp2+build03
+
+ -- Juyung Seo <juyung.seo@samsung.com> Tue, 14 Dec 2010 14:59:17 +0900
+
+edbus (1.0.0.001+svn.55010slp2+build02) unstable; urgency=low
+
+ * Merged sbs-for-master.
+ * Git: 165.213.180.234:/git/slp/pkgs/edbus
+ * Tag: edbus_1.0.0.001+svn.55010slp2+build02
+
+ -- Juyung Seo <juyung.seo@samsung.com> Thu, 02 Dec 2010 17:34:33 +0900
+
+edbus (1.0.0.001+svn.55010slp2+build01) unstable; urgency=low
+
+ * [SVN 55010 Merge]
+ * Update to SVN Revision 55010.
+ * Git: 165.213.180.234:/git/slp/pkgs/edbus
+ * Tag: edbus_1.0.0.001+svn.55010slp2+build01
+
+ -- Myoungwoon Kim <myoungwoon.kim@samsung.com> Thu, 02 Dec 2010 14:33:40 +0900
+
+edbus (1.0.0.001+svn.51480slp2+build03) unstable; urgency=low
+
+ * [SVN 54772 Merge]
+ * Update to SVN Revision 54772.
+ * Git: 165.213.180.234:/git/slp/pkgs/edbus
+ * Tag: edbus_1.0.0.001+svn.51480slp2+build03
+
+ -- Juyung Seo <juyung.seo@samsung.com> Fri, 26 Nov 2010 15:48:48 +0900
+
+edbus (1.0.0.001+svn.51480slp2+build02) unstable; urgency=low
+
+ * add as-needed
+ * Git: 165.213.180.234:/git/slp/pkgs/edbus
+ * Tag: edbus_1.0.0.001+svn.51480slp2+build02
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Wed, 15 Sep 2010 10:54:47 +0900
+
+edbus (1.0.0.001+svn.51480slp2+build01) unstable; urgency=low
+
+ * efl 1.0 alpha upgrade
+ * Git: 165.213.180.234:/git/slp/pkgs/edbus
+ * Tag: edbus_1.0.0.001+svn.51480slp2+build01
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Tue, 31 Aug 2010 22:49:54 +0900
+
+edbus (0.5.0.060+svn.49544slp2+s1-3build05) unstable; urgency=low
+
+ * src/bin/Makefile/am fixed: added missed dependencies for the libedbus
+
+ -- Tomasz Fujak <t.fujak@samsung.com> Thu, 09 Sep 2010 14:29:19 +0900
+
+edbus (0.5.0.060+svn.49544slp2+3build05) unstable; urgency=low
+
+ * Packaging.
+ * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/e_dbus
+ * Tag: edbus_0.5.0.060+svn.49544slp2+3build05
+
+ -- Daniel Juyung Seo <juyung.seo@samsung.com> Thu, 10 Jun 2010 21:44:35 +0900
+
+edbus (0.5.0.060+svn.49544slp2+3build04) unstable; urgency=low
+
+ * Packaging.
+ * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/edbus
+ * Tag: edbus_0.5.0.060+svn.49544slp2+3build04
+
+ -- Daniel Juyung Seo <juyung.seo@samsung.com> Thu, 10 Jun 2010 21:09:21 +0900
+
+edbus (0.5.0.060+svn.49544slp2+3build03) unstable; urgency=low
+
+ * Packaging.
+ * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/edbus
+ * Tag: edbus_0.5.0.060+svn.49544slp2+3build03
+
+ -- Daniel Juyung Seo <juyung.seo@samsung.com> Thu, 10 Jun 2010 21:03:50 +0900
+
+edbus (0.5.0.060+svn.49544slp2+3build02) unstable; urgency=low
+
+ * Packaging.
+ * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/edbus
+ * Tag: edbus_0.5.0.060+svn.49544slp2+3build02
+
+ -- Daniel Juyung Seo <juyung.seo@samsung.com> 목, 10 6월 2010 21:00:50 +0900
+
+edbus (0.5.0.060+svn.49544slp2+3) unstable; urgency=low
+
+ * Packaging.
+ * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/edbus
+ * Tag: edbus_0.5.0.060+svn.49544slp2+3
+
+ -- Daniel Juyung Seo <juyung.seo@samsung.com> Thu, 10 Jun 2010 20:46:53 +0900
+
+edbus (0.5.0.060+svn.49544slp2+2) unstable; urgency=low
+
+ * Packaging.
+ * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/edbus
+ * Tag: edbus_0.5.0.060+svn.49544slp2+2
+
+ -- Daniel Juyung Seo <juyung.seo@samsung.net> Thu, 10 Jun 2010 20:46:08 +0900
+
+edbus (0.5.0.060+svn.49544slp2+1) unstable; urgency=low
+
+ * Packaging.
+ * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/edbus
+ * Tag: edbus_0.5.0.060+svn.49544slp2+1
+
+ -- Daniel Juyung Seo <juyung.seo@smasung.net> Thu, 10 Jun 2010 20:45:22 +0900
+
+edbus (0.5.0.060+svn.49544slp2+0) unstable; urgency=low
+
+ * Update opensource EFL from SVN
+ * SVN revision: 49544 (Total EFL revision: 49550)
+ * Tag: 0.5.0.060+svn.49544slp2+0
+
+ -- Daniel Juyung Seo <juyung.seo@smasung.net> Thu, 10 Jun 2010 15:50:38 +0900
+
+edbus (0.5.0.060+svn20100304slp2) unstable; urgency=low
+
+ * change package version
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Thu, 25 Mar 2010 15:44:48 +0900
+
+edbus (0.5.0.060+svn20100304-1) unstable; urgency=low
+
+ * EFL_update_revision_46864
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Wed, 10 Mar 2010 16:06:37 +0900
+
+edbus (0.5.0.060+svn20100203-3) unstable; urgency=low
+
+ * add debug package
+
+ -- wonguk jeong <wonguk.jeong@samsung.com> Mon, 08 Feb 2010 15:14:57 +0900
+
+edbus (0.5.0.060+svn20100203-2) unstable; urgency=low
+
+ * repack
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Thu, 04 Feb 2010 20:30:37 +0900
+
+edbus (0.5.0.060+svn20100203-1) unstable; urgency=low
+
+ * EFL_update_revision_45828
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Wed, 03 Feb 2010 16:39:23 +0900
+
+edbus (0.5.0.060+svn20100119-1) unstable; urgency=low
+
+ * EFL_update_revision_45322
+
+ -- Jihoon Kim <jihoon48.kim@samsung.com> Tue, 19 Jan 2010 20:44:50 +0900
+
+edbus (0.5.0.060+svn20100111-3) unstable; urgency=low
+
+ * reupload EFL i686
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Tue, 12 Jan 2010 17:35:44 +0900
+
+edbus (0.5.0.060+svn20100111-2) unstable; urgency=low
+
+ * reupload EFL
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Mon, 11 Jan 2010 22:17:08 +0900
+
+edbus (0.5.0.060+svn20100111-1) unstable; urgency=low
+
+ * update EFL revision 45026
+
+ -- Jaehwan Kim <jae.hwan.kim@samsung.com> Mon, 11 Jan 2010 13:28:07 +0900
+
+edbus (0.5.0.060+svn20091229-1) unstable; urgency=low
+
+ * update EFL
+
+ -- jaehwan kim <jae.hwan.kim@samsung.com> Tue, 29 Dec 2009 14:29:07 +0900
+
+edbus (0.5.0.060+svn20091112-2) unstable; urgency=low
+
+ * svn stable version
+
+ -- Sangho Park <sangho.g.park@samsung.com> Thu, 19 Nov 2009 19:11:30 +0900
+
+edbus (0.5.0.060+svn20091112-1) unstable; urgency=low
+
+ * New version
+
+ -- Sangho Park <sangho.g.park@samsung.com> Fri, 13 Nov 2009 09:05:37 +0900
+
+edbus (0.5.0.060+svnYYYYMMDD-1) unstable; urgency=low
+
+ * New version
+
+ -- quaker <quaker66@gmail.com> Thu, 22 Apr 2009 18:13:37 +0100
+
+edbus (0.5.0.050+svnYYYYMMDD-1) unstable; urgency=low
+
+ * Clean up changelog
+
+ -- quaker <quaker66@gmail.com> Tue, 21 Apr 2009 19:16:16 +0100
--- /dev/null
+Source: edbus
+Section: libs
+Priority: optional
+Maintainer: Jaehwan Kim <jae.hwan.kim@samsung.com>, Juyung Seo <juyung.seo@samsung.com>, Myoungwoon Kim <myoungwoon.kim@samsung.com>, Mike McCormack <mj.mccormack@samsung.com>, Jeonghyun Yun <jh0506.yun@samsung.com>, Hyoyoung Chang <hyoyoung.chang@samsung.com>
+Build-Depends: debhelper (>= 6), cdbs, libecore-dev, libdbus-1-dev,
+ libevas-dev, libeina-dev (>= 0.0.2.060+svn20100304), pkg-config, libtool
+Standards-Version: 3.8.1
+Homepage: http://enlightenment.org
+
+Package: libedbus-dev
+Section: libdevel
+Architecture: any
+Depends: ${misc:Depends}, libedbus (= ${binary:Version}), libdbus-1-dev,
+ libeina-dev, libecore-dev, libevas-dev
+Description: D-Bus and HAL wrapper libraries for use with the EFL - Development files
+ Wrappers around D-Bus to ease integrating D-Bus with EFL based applications.
+ .
+ This packages contains headers and static libraries for libedbus, libehal and
+ libenotify
+
+Package: libedbus
+Conflicts: libedbus0
+Architecture: any
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Description: D-Bus and HAL wrapper libraries for use with the EFL
+ This package contains:
+ - libedbus0 and libehal0 : D-Bus and HAL-related wrappers to ease integrating
+ D-Bus and HAL with EFL-based applications
+ - libenotify0 : provides an EFL-based notification support
+
+Package: libedbus-dbg
+Section: debug
+Architecture: any
+Depends: ${misc:Depends}, libedbus (= ${binary:Version})
+Description: D-Bus and HAL wrapper libraries for use with the EFL - Development files
+ Wrappers around D-Bus to ease integrating D-Bus with EFL based applications.
+ .
+ This package is debug package
--- /dev/null
+This package was debianized by Debian Pkg-e Team <pkg-e-devel@lists.alioth.debian.org>
+Wed, 27 Feb 2008 23:07:21 +0000
+
+It was downloaded from http://download.enlightenment.org/snapshots/LATEST/
+
+Upstream Author: Brian Mattern <rephorm@rephorm.com>
+
+Copyright:
+
+ Copyright (C) 2006 Brian Mattern and various contributors
+
+License:
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to
+ deal in the Software without restriction, including without limitation the
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ sell copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies of the Software and its Copyright notices. In addition publicly
+ documented acknowledgment must be given that this software has been used if no
+ source code of this software is made available publicly. This includes
+ acknowledgments in either Copyright notices, Manuals, Publicity and Marketing
+ documents or any documentation provided with any product containing this
+ software. This License does not apply to any software that links to the
+ libraries provided by this software (statically or dynamically), but only to
+ the software provided.
+
+ Please see the COPYING.PLAIN for a plain-english explanation of this notice
+ and it's intent.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+On Debian systems, the complete text of the BSD License can be found
+in `/usr/share/common-licenses/BSD'.
+
+The Debian packaging is:
+ (C) 2006 2007,Debian Pkg-e Team <pkg-e-devel@lists.alioth.debian.org>
+and is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
--- /dev/null
+debian/tmp/usr/include/e_dbus-1/*
+debian/tmp/usr/lib/pkgconfig/*.pc
+debian/tmp/usr/lib/*.a
+debian/tmp/usr/lib/*.so
--- /dev/null
+debian/tmp/usr/lib/*.so.*
--- /dev/null
+libedbus 1 libedbus (>= 0.5.0.060+svn20100304)
+libehal 1 libedbus (>= 0.5.0.060+svn20100304)
+libenotify 1 libedbus (>= 0.5.0.060+svn20100304)
+libebluez 1 libedbus (>= 0.5.0.060+svn20100304)
+libeofono 1 libedbus (>= 0.5.0.060+svn20100304)
+libeukit 1 libedbus (>= 0.5.0.060+svn20100304)
+libeconnman0_7x 1 libedbus (>= 0.5.0.060+svn20100304)
--- /dev/null
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/autotools.mk
+
+DEB_CONFIGURE_SCRIPT := ./autogen.sh
+DEB_MAKE_CLEAN_TARGET := distclean
+DEB_CONFIGURE_EXTRA_FLAGS :=
+CFLAGS += -fvisibility=hidden -fPIC
+LDFLAGS += -fvisibility=hidden -Wl,--hash-style=both -Wl,--as-needed
+
+clean::
+ [ ! -f Makefile ] || make distclean
--- /dev/null
+# 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
--- /dev/null
+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
--- /dev/null
+/*
+ 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%;
+}
+
--- /dev/null
+
+ <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 ©$year Enlightenment</td>
+ <td class="generated">Docs generated $datetime</td>
+ </tr></table>
+ </div>
+
+
+</body>
+</html>
--- /dev/null
+<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">
--- /dev/null
+/*
+ * 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%;
+}
+
--- /dev/null
+%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
--- /dev/null
+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@
--- /dev/null
+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@
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+ <assign>
+ <filesystem path="/usr/bin/e_dbus_async_client_test" exec_label="none" />
+ <filesystem path="/usr/bin/e_dbus_async_server_test" exec_label="none" />
+ <filesystem path="/usr/bin/e_dbus_bluez_test" exec_label="none" />
+ <filesystem path="/usr/bin/e_dbus_connman0_7x_test" exec_label="none" />
+ <filesystem path="/usr/bin/e_dbus_notification_daemon" exec_label="none" />
+ <filesystem path="/usr/bin/e_dbus_notify" exec_label="none" />
+ <filesystem path="/usr/bin/e_dbus_ofono_test" exec_label="none" />
+ <filesystem path="/usr/bin/e_dbus_test" exec_label="none" />
+ <filesystem path="/usr/bin/e_dbus_test_client" exec_label="none" />
+ <filesystem path="/usr/bin/e_dbus_ukit_test" exec_label="none" />
+ <filesystem path="/usr/bin/e-notify-send" exec_label="none" />
+ </assign>
+</manifest>
--- /dev/null
+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@
--- /dev/null
+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@
--- /dev/null
+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@
--- /dev/null
+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@
--- /dev/null
+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@
--- /dev/null
+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
--- /dev/null
+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])
+
+])
--- /dev/null
+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])
+
+])
--- /dev/null
+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
--- /dev/null
+#sbs-git:slp/pkgs/e/edbus edbus 1.0.0.001+svn.69045slp2+build01 706f4acfdaf1b818e2387701a993eca929051358
+Name: edbus
+Summary: D-Bus and HAL wrapper libraries for EFL
+Version: 1.6.0+svn.76526slp2+build07
+Release: 1
+VCS: framework/uifw/edbus#1.6.0+svn.76526slp2+build06-0-gf8cc99cf55301331d3465870098a27d937bdb9aa
+Group: System/Libraries
+License: BSD
+Source0: %{name}-%{version}.tar.gz
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+BuildRequires: ecore-devel
+BuildRequires: eina-devel
+BuildRequires: evas-devel
+BuildRequires: dbus-devel
+
+
+%description
+D-Bus and HAL wrapper libraries for use with the EFL
+
+
+
+%package devel
+Summary: D-Bus and HAL wrapper libraries for EFL (devel)
+Group: Development/Libraries
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+D-Bus and HAL wrapper libraries for use with the EFL (devel)
+
+
+%prep
+%setup -q
+
+
+%build
+export CFLAGS+=" -fvisibility=hidden -fPIC"
+export LDFLAGS+=" -fvisibility=hidden -Wl,--hash-style=both -Wl,--as-needed"
+
+%autogen --disable-static
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+mkdir -p %{buildroot}/usr/share/license
+cp %{_builddir}/%{buildsubdir}/COPYING %{buildroot}/usr/share/license/%{name}
+
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%defattr(-,root,root,-)
+%{_bindir}/e-*
+%{_bindir}/e_*
+%{_libdir}/libe*.so.*
+/usr/share/e_dbus/logo.png
+%manifest %{name}.manifest
+/usr/share/license/%{name}
+
+%files devel
+%defattr(-,root,root,-)
+%{_libdir}/libebluez.so
+%{_libdir}/libeconnman0_7x.so
+%{_libdir}/libedbus.so
+%{_libdir}/libehal.so
+%{_libdir}/libenotify.so
+%{_libdir}/libeofono.so
+%{_libdir}/libeukit.so
+%{_libdir}/pkgconfig/ebluez.pc
+%{_libdir}/pkgconfig/econnman-0.7x.pc
+%{_libdir}/pkgconfig/edbus.pc
+%{_libdir}/pkgconfig/ehal.pc
+%{_libdir}/pkgconfig/enotify.pc
+%{_libdir}/pkgconfig/eofono.pc
+%{_libdir}/pkgconfig/eukit.pc
+
+%{_includedir}/e_dbus-1/E_Bluez.h
+%{_includedir}/e_dbus-1/connman0_7x/E_Connman.h
+%{_includedir}/e_dbus-1/E_DBus.h
+%{_includedir}/e_dbus-1/E_Hal.h
+%{_includedir}/e_dbus-1/E_Notification_Daemon.h
+%{_includedir}/e_dbus-1/E_Notify.h
+%{_includedir}/e_dbus-1/E_Ofono.h
+%{_includedir}/e_dbus-1/E_Ukit.h
--- /dev/null
+MAINTAINERCLEANFILES = Makefile.in
+SUBDIRS = lib bin
--- /dev/null
+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
+
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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, ðernet_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, ðernet_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, ðernet_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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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()
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+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
--- /dev/null
+#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 */
--- /dev/null
+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
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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);
+}
+
--- /dev/null
+#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);
+}
+
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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);
+}
+
--- /dev/null
+#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);
+}
+
--- /dev/null
+#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);
--- /dev/null
+#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 */
--- /dev/null
+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
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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);
+}
+
--- /dev/null
+#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);
+}
+
--- /dev/null
+#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);
--- /dev/null
+#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);
+}
+
--- /dev/null
+#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);
+}
--- /dev/null
+#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);
+}
--- /dev/null
+#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 8
+
+ 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
+ * @return 1 or greater on success, 0 otherwise
+ *
+ * This function sets up all the E_DBus library. It returns 0 on
+ * failure, otherwise it returns the number of times it has already
+ * been called.
+ *
+ * When E_DBus is not used anymore, call e_dbus_shutdown() to shut down
+ * the E_DBus library.
+ */
+EAPI int e_dbus_init(void);
+
+/**
+ * Shutdown e_dbus.
+ * @return 0 if e_dbus shuts down, greater than 0 otherwise.
+ *
+ * This function shuts down the E_DBus library. It returns 0 when it has
+ * been called the same number of times as e_dbus_init().
+ */
+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
--- /dev/null
+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
--- /dev/null
+#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(E_DBus_Connection *cd)
+{
+ 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, NULL);
+ 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);
+ e_dbus_connection_free(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;
+
+ // FIXME: this is workaround
+ while (shared_connections[DBUS_BUS_SESSION] &&
+ shared_connections[DBUS_BUS_SESSION]->refcount >= 1)
+ {
+ e_dbus_connection_close(shared_connections[DBUS_BUS_SESSION]);
+ }
+ // FIXME: this is workaround
+ while (shared_connections[DBUS_BUS_SYSTEM] &&
+ shared_connections[DBUS_BUS_SYSTEM]->refcount >= 1)
+ {
+ e_dbus_connection_close(shared_connections[DBUS_BUS_SYSTEM]);
+ }
+
+ 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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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 = NULL;
+
+ 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));
+ if (pdata)
+ {
+ 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);
+}
--- /dev/null
+#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;
+ }
+ EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, 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;
+ }
+ EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, 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;
+ }
+ EINA_SAFETY_ON_NULL_RETURN_VAL(bus, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(object_path, 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;
+ }
+ EINA_SAFETY_ON_NULL_RETURN_VAL(name, 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;
+ }
+ EINA_SAFETY_ON_NULL_RETURN_VAL(name, 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;
+}
--- /dev/null
+#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");
+}
+
--- /dev/null
+#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
--- /dev/null
+#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;
+
+ 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_bus_add_match(conn->conn, sh->match, NULL);
+
+ 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);
+}
--- /dev/null
+#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;
+ }
+}
--- /dev/null
+#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
--- /dev/null
+<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"><<a href="mailto:david@fubar.dk">david@fubar.dk</a>></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"><match key="some_property"
+ [string|int|bool|..]="required_value" >
+ </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"><[merge|append|prepend|addset] key="some_property"
+ type="[string|int|bool|..]">
+ </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"><match></code>,
+ <code class="literal"><merge></code>, <code class="literal"><append></code>,
+ <code class="literal"><prepend></code>
+ and <code class="literal"><addset></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"><match></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"><match key="foo.bar" string="baz"></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"><match key="system.hardware.product" string_outof="Satellite A30;Portable PC"></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"><match key="usb.product_id" int_outof="0x1007;0x1008;0x1009"></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"><match key="foo.bar" exists="true"></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"><match key="system.hardware.product" contains_outof="D600;D610;C540"></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"><match key="system.hardware.product" prefix_outof="1860;2366;2371"></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"><merge></code>, <code class="literal"><append></code>,
+ <code class="literal"><prepend></code>
+ and <code class="literal"><addset></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"><merge key="foo.bar" type="string">baz</merge></code>
+ will merge the value 'baz' into the property 'foo.bar'.
+ </p></li><li><p>
+ <code class="literal">strlist</code> - For <code class="literal"><merge></code> the value is
+ copied to the property and the current property will be overwritten. For
+ <code class="literal"><append></code>
+ and <code class="literal"><prepend></code> the value is
+ append or prepend to the list as new
+ item. For <code class="literal"><addset></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"><copy_property></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"><merge key="foo.bar" type="copy_property">@info.parent:baz.bat</merge></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"><remove></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"><remove key="foo.bar" type="strlist">bla</remove></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"><iface>.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"><iface>.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"><iface>.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"><iface>.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"><iface>.*</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' -> '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>
--- /dev/null
+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
--- /dev/null
+#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;
+}
--- /dev/null
+#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
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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;
+}
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+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
--- /dev/null
+#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);
+}
+
--- /dev/null
+#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);
+}
--- /dev/null
+#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
--- /dev/null
+#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, ¬ification_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;
+}
+
--- /dev/null
+<?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>>= 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>>= 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>>= 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>< 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>>= 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>>= 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>
--- /dev/null
+#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(¬e->app_name, app_name);
+}
+
+EAPI void
+e_notification_app_icon_set(E_Notification *note, const char *app_icon)
+{
+ loginit();
+ eina_stringshare_replace(¬e->app_icon, app_icon);
+}
+
+EAPI void
+e_notification_summary_set(E_Notification *note, const char *summary)
+{
+ loginit();
+ eina_stringshare_replace(¬e->summary, summary);
+}
+
+EAPI void
+e_notification_body_set(E_Notification *note, const char *body)
+{
+ loginit();
+ eina_stringshare_replace(¬e->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;
+}
+
--- /dev/null
+#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 */
--- /dev/null
+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
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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);
+}
+
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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);
+}
+
--- /dev/null
+#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);
+}
+
--- /dev/null
+#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);
--- /dev/null
+#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);
+}
+
--- /dev/null
+#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
--- /dev/null
+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
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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
--- /dev/null
+#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);
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}