summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--NEWS1329
-rwxr-xr-xautogen.sh22
-rw-r--r--configure.ac35
-rw-r--r--docs/reference/telepathy-glib-sections.txt58
-rw-r--r--examples/extensions/Makefile.am26
-rw-r--r--m4/Makefile.am3
-rw-r--r--m4/shave.m477
-rw-r--r--shave-libtool.in69
-rw-r--r--shave.in79
-rw-r--r--telepathy-glib/Makefile.am36
-rw-r--r--telepathy-glib/account-internal.h39
-rw-r--r--telepathy-glib/account-manager-internal.h40
-rw-r--r--telepathy-glib/account-manager.c1385
-rw-r--r--telepathy-glib/account-manager.h38
-rw-r--r--telepathy-glib/account.c2626
-rw-r--r--telepathy-glib/account.h118
-rw-r--r--telepathy-glib/signals-marshal.list4
-rw-r--r--telepathy-glib/telepathy-glib-uninstalled.pc.in2
-rw-r--r--telepathy-glib/telepathy-glib.pc.in2
-rw-r--r--telepathy-glib/versions/0.9.0.abi56
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/dbus/Makefile.am9
-rw-r--r--tests/dbus/account-manager.c23
-rw-r--r--tests/dbus/account.c101
-rw-r--r--tools/Makefile.am20
26 files changed, 4538 insertions, 1664 deletions
diff --git a/.gitignore b/.gitignore
index 6675ac5e6..f5e676da5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -70,5 +70,3 @@ tests/test-*
tests/tools/actual.h
tests/tools/actual-body.h
tools/telepathy-glib-env
-shave
-shave-libtool
diff --git a/NEWS b/NEWS
index 573caf6f6..aec3d2f33 100644
--- a/NEWS
+++ b/NEWS
@@ -1,10 +1,16 @@
-telepathy-glib 0.8.1 (UNRELEASED)
+telepathy-glib 0.9.1 (UNRELEASED)
=================================
-The "TpConnectionManager was not my finest hour" release.
-
Fixes:
+* Corrected the GLib dependency to 2.20 (this was also needed for 0.9.0,
+ but that fact was undocumented) (smcv)
+
+* Corrected the error message given when a write-only D-Bus property
+ is read (Pekka Pessi)
+
+* Work around GLib 2.20 being less const-correct than 2.22 (jonny)
+
* fd.o #23853: if a connection manager is discovered not to be running while
TpConnectionManager has a ListProtocols call in-flight, then a new instance
of the CM starts up and replies to that call, don't crash with an assertion
@@ -22,8 +28,28 @@ Fixes:
if they lack the SECRET flag, as was already done when reading .manager
files (smcv)
-* Corrected the error message given when a write-only D-Bus property
- is read (Pekka Pessi)
+telepathy-glib 0.9.0 (2009-09-28)
+=================================
+
+The "purging all the lies" release.
+
+Dependencies:
+
+* GLib 2.20 is now required.
+* telepathy-glib now links to GIO as well as GLib and GObject (in practice
+ they're packaged together, and we already depended on a new enough GLib
+ version that it would come with GIO).
+
+Enhancements:
+
+* TpAccountManager, TpAccount: add convenience API similar to libempathy's
+ (jonny, with contributions from wjt/danni/sjoerd/smcv)
+
+* telepathy-glib now uses Automake 1.11's "silent rules" feature for
+ kernel-style output; as a result, we no longer use shave. If you were
+ previously using --enable-shave to get prettier output, use
+ --enable-silent-rules instead, and upgrade to Automake >= 1.11 if you will
+ be altering the build system. (jonny)
telepathy-glib 0.8.0 (2009-09-24)
=================================
@@ -61,1296 +87,3 @@ Changes since 0.7.37:
* spec: update from 0.17.28 to 0.18.0 (no real changes) (smcv)
* ContactList example CM: fix a crash during shutdown (andrunko)
* StreamedMedia example CM: check for direction changes correctly (andrunko)
-
-telepathy-glib 0.7.37 (2009-09-14)
-==================================
-
-The "Lego Batman" release.
-
-Enhancements:
-
-* Update to telepathy-spec 0.17.28
- * add ContactCapabilities interface
- * add InitialVideo, InitialAudio, ImmutableStreams properties to
- StreamedMedia
- * add TP_CHANNEL_CALL_STATE_FLAG_IN_PROGRESS
-
-* Set the debug domain for telepathy-glib to tp-glib/$category, e.g.
- tp-glib/connection for TpConnection and TpBaseConnection (jonny)
-
-Fixes:
-
-* fd.o #23843: make tp_debug_sender_log_handler with exclude=NULL include
- everything, rather than nothing (smcv)
-
-telepathy-glib 0.7.36 (2009-09-03)
-==================================
-
-The "yes, it's a phone" release.
-
-Enhancements:
-
-* Add TpDebugSender, along with the lower-level TpSvcDebug interface that it
- uses (jonny)
-
-* Clarify when tp_proxy_signal_connection_disconnect is safe to call (smcv)
-
-* Add support for simulating DTMF and Hold support in the 'callable' example
- connection manager (andrunko)
-
-* fd.o #21327: truncate the ChangeLog at version 0.6 to stop it being so huge,
- and force ISO date format (wjt)
-
-Fixes:
-
-* If the bus name for a Connection would be too long, hash the unique name
- provided by the CM, instead of crashing (daf)
-
-* fd.o #23524: don't introspect a TpConnectionManager twice in parallel,
- avoiding an assertion failure (wjt)
-
-* TpChannel: don't disconnect from a TpProxySignalConnection that's already
- gone, fixing a crash (smcv)
-
-* tp_connection_manager_idle_read_manager_file: avoid using the
- TpConnectionManager after it may have been disposed (sjoerd)
-
-* TpBaseConnection: Allow GetInterfaces() to succeed before CONNECTED (smcv)
-
-telepathy-glib 0.7.35 (2009-08-18)
-==================================
-
-The "dance to the sound of sirens" release.
-
-API changes:
-
-* fd.o #17751: TpBaseConnection no longer guarantees that the self-handle is
- set to 0 when the state changes to DISCONNECTED; instead, the self-handle
- remains valid until the connection is disposed, so that connection managers
- can use it during teardown. (cassidy)
- - This change will cause assertion failures on disconnection in
- telepathy-sofiasip older than 0.5.17, and in telepathy-gabble older than
- 0.7.9.
-
-Enhancements:
-
-* Add tp_dbus_daemon_list_names() and tp_dbus_daemon_list_activatable_names(),
- which are more efficient (and more const-correct) versions of the
- corresponding autogenerated tp_cli_dbus_daemon methods (smcv)
-
-* Support the Hold interface in the "callable" example CM (andrunko)
-
-Fixes:
-
-* Finally make tp_dbus_daemon_watch_name_owner bind to NameOwnerChanged
- selectively, for reduced wakeups. To take advantage of this, you should
- avoid using all functions that start with tp_cli_dbus_daemon_; file bugs
- to request more replacement functions in the tp_dbus_daemon namespace. (smcv)
-
-* Fix a memory leak in tp_dbus_daemon_watch_name_owner (smcv)
-
-* fd.o #9812: TpDynamicHandleRepo: use tp_dbus_daemon_watch_name_owner for
- reduced wakeups (smcv)
-
-* In TpDynamicHandleRepo, if a client holds handles then immediately crashes,
- release those handles as soon as we find out that it's gone (smcv)
-
-* fd.o #22957: fix compilation in some non-gcc compilers
- (based on a patch from Elaine Xiong)
-
-* As per telepathy-spec 0.17.27, represent connection status reason NAME_IN_USE
- as TP_ERROR_CONNECTION_REPLACED or TP_ERROR_ALREADY_CONNECTED (as
- appropriate), not as TP_ERROR_NOT_YOURS, so that NotYours can safely be given
- special handling (smcv)
-
-telepathy-glib 0.7.34 (2009-08-16)
-==================================
-
-The "secret lack of example detected" release.
-
-Enhancements:
-
-* Updated to telepathy-spec 0.17.27 (smcv)
- - generate code for Connection.Interface.Location
- - omit Debug interface from code-generation for now: it will be enabled in a
- future release when we have reference client- and service-side
- implementations (possibly called TpDebugReceiver and TpDebugSender)
- - add more errors
- - generate code for Handler.Capabilities property
-
-* Add macros for static assertions (tp_verify, tp_verify_true,
- tp_verify_statement) to util.h (smcv, adapted from gnulib)
-
-* Make the allocation model for tp_dbus_properties_mixin_make_properties_hash
- part of our ABI guarantee (smcv)
-
-* Add a GType macro TP_ARRAY_TYPE_OBJECT_PATH_LIST (wjt)
-
-Fixes:
-
-* fd.o #23164: don't unref a NULL DBusMessage (wjt)
-
-* Get tp_intset_iter_init and tp_intset_iter_reset into the documentation (smcv)
-
-* Make omitted CM parameters that have a default indistinguishable from
- explicitly-passed parameters with that value, removing the need to specify
- the default in the Connection as well (sjoerd)
-
-* fd.o #22889: reduce introspection round-trips (wjt)
-
-* Fix header guard in debug.h (dilinger)
-
-* fd.o #18091: for interfaces with D-Bus methods, document how to write a
- complete interface init function (smcv)
-
-* Fix a rare crash when a TpProxyPendingCall is cancelled before the
- DBusGProxyCall is provided (smcv)
-
-telepathy-glib 0.7.33 (2009-06-26)
-==================================
-
-The "please be careful when handling the sun" release.
-
-Fixes:
-
-* Fixed a test failure in test-params-cm on certain architectures, including
- powerpc and sparc (smcv)
-
-* Fixed an assertion failure in TpConnection if StatusChanged to CONNECTED is
- followed immdiately by GetStatus returning CONNECTED (smcv)
-
-telepathy-glib 0.7.32 (2009-06-12)
-==================================
-
-The "cake wars" release.
-
-Enhancements:
-
-* fd.o #22208: Updated to telepathy-spec 0.17.26 (smcv)
-
-* Added generated service-side bindings for AccountManager, Account,
- ChannelDispatcher, ChannelDispatchOperation, ChannelRequest and Client (smcv)
-
-* Added minimal versions of TpAccountManager, TpAccount,
- TpChannelDispatcher, TpChannelDispatchOperation, TpChannelRequest and
- TpClient (smcv)
-
-* fd.o #22205: Added support for deprecating or removing _run_ methods in code
- generation (smcv)
-
-* Added flymake support (jonnylamb)
-
-* fd.o #22230: Added support for byte ('y') parameters to CMs (smcv)
-
-Fixes:
-
-* Made sure _gen/error-str.h and .c end with a newline, fixing compilation with
- certain compilers (smcv)
-
-* fd.o #19741: Documented client-side handle reference counting (wjt)
-
-* fd.o #21977: Removed duplicate mention of media-interfaces.h in Makefile.am
- (Patryk Zawadzki)
-
-* fd.o #22121: made tp_channel_dispose properly idempotent (wjt)
-
-* Removed dead code for introspecting alias flags (smcv)
-
-* fd.o #22182: Fixed a potential use-after-free in the callable example CM
- (smcv)
-
-Release notes for projects using code generation:
-
-* After updating to this version of glib-client-gen.py, _run_ methods will no
- longer be generated by default. To get the behaviour of older versions, run
- it with the new --generate-reentrant option; to get the methods present
- but deprecated, use an option like
- --deprecate-reentrant=FOO_DISABLE_DEPRECATED (which means the _run_ methods
- are marked with G_GNUC_DEPRECATED, and will not be available at all if
- FOO_DISABLE_DEPRECATED is defined).
-
-telepathy-glib 0.7.31 (2009-05-27)
-==================================
-
-The "this beer tastes of Stilton!" release.
-
-Enhancements:
-
-* Added TP_ERROR_STR_* constants corresponding to the members of the
- TpError enum, and tp_error_get_dbus_name() mapping the latter to the
- former (cassidy/wjt)
-
-* Updated to telepathy-spec 0.17.25, adding ConnectionRefused, ConnectionFailed
- and ConnectionLost errors, and the new-style StreamTube and DBusTube channel
- types (cassidy)
-
-* Made tp_g_key_file_get_int64 and _uint64 into public API for Mission
- Control's benefit (smcv)
-
-Fixes:
-
-* Changed the dbus_daemon member of TpProxy to be removed in dispose, rather
- than just after the invalidated signal (smcv)
-
-* Fixed a null pointer dereference if a TpConnectionManager is resurrected
- during dispose (smcv)
-
-* Fixed a use-after-free when the user-supplied object in
- tp_connection_manager_call_when_ready is destroyed after the CM becomes
- ready (smcv)
-
-* Fixed tp_dbus_daemon_request_name, tp_dbus_daemon_release_name and
- _tp_dbus_daemon_get_name_owner to fail gracefully if the TpDBusDaemon has
- been invalidated (smcv)
-
-telepathy-glib 0.7.30 (2009-05-18)
-==================================
-
-The "slowing down but with a sense of speeding up" release.
-
-API changes:
-
-* tp_proxy_add_interface_by_id() may not be called on an invalidated proxy. (It
- never made sense to do this, but now telepathy-glib will complain if you do.)
-
-Enhancements:
-
-* Added tp_dbus_daemon_request_name() and tp_dbus_daemon_release_name(). (Fixes
- fd.o#21771.)
-
-* Update to telepathy-spec 0.17.23, adding the Terminated error.
-
-* Added optional support for Shave, to give kernel-style pretty make output.
- (This is disabled by default; to enable it, pass --enable-shave to configure.)
- (Jonny Lamb)
-
-* Channel introspection will now fail more quickly when the channel is
- invalidated.
-
-Fixes:
-
-* Generated GInterfaces now install type information sooner, fixing a bug where
- object construction could make dbus-glib assert. (Ross Burton)
-
-* fd.o#21792: tp_presence_mixin_simple_presence_fill_contact_attributes asserts
- if get_contact_statuses returns NULL.
-
-telepathy-glib 0.7.29 (2009-04-03)
-==================================
-
-The "sense of adventure working perfectly and sensing no adventures" release.
-
-Enhancements:
-
-* TpBaseConnectionManager, tp_cm_param_setter_offset: support parameters of
- various extra types - object path, double, 64-bit signed and unsigned
- integer, array of strings, array of bytes - and add regression tests
-
-* TpContact: enhance documentation to spell out that change notification is
- via GObject::notify::alias etc.
-
-* tp_asv_new(), a shorthand for creating hash tables from strings to
- slice-allocated GValues, along with tp_asv_set_* and tp_asv_take_* helpers to
- add entries to such hash tables. (Fixes fd.o#20942)
-
-telepathy-glib 0.7.28 (2009-03-24)
-==================================
-
-The "a surprisingly meaty courgette" release.
-
-API changes:
-
-* Use the prefix for D-Bus errors specified by telepathy-spec, not something
- telepathy-glib made up (changing .Errors to the correct .Error). This was
- a regression in telepathy-glib 0.7.1.
-
- Expected impact of this change:
- * Connection managers will emit the correct errors as soon as the
- telepathy-glib shared library is upgraded
- * Clients that use TpConnection, TpChannel etc. will expect the correct
- errors as soon as the shared library is upgraded
- * Clients that match errors by string value using TP_ERROR_PREFIX will have
- to be recompiled against the new telepathy-glib, but should have sane
- fallback behaviour to treat the correct error strings as an unknown error
-
-Enhancements:
-
-* Update to telepathy-spec 0.17.22, adding
- TP_ARRAY_TYPE_SOCKET_ADDRESS_IP_LIST, TP_ARRAY_TYPE_STRING_STRING_MAP_LIST,
- TP_STRUCT_TYPE_SOCKET_ADDRESS_IP
-
-* Extend the 'callable' example connection manager to support simulated
- incoming calls, support simulated contacts who never answer, are busy or
- terminate the call, and comply with telepathy-spec 0.17.22
-
-Fixes:
-
-* fd.o #20729: csh (chatroom) example connection manager: comply with
- telepathy-spec 0.17.21 by always allowing the user to leave the Group
-
-* Cancel GetParameters call if the CM crashes, fixing an assertion failure
- in tp_connection_manager_continue_introspection
-
-telepathy-glib 0.7.27 (2009-03-17)
-==================================
-
-The "sliced woot" release.
-
-Enhancements:
-
-* fd.o #18220: make it much less verbose to construct string/variant maps
- (a{sv}) by adding functions like tp_g_value_slice_new_uint(), which are a
- shortcut for a sequence like tp_g_value_slice_new (G_TYPE_UINT) followed by
- g_value_set_uint
-
-* Make example connection managers installable (they might be useful for
- testing UIs - use ./configure --enable-installed-examples if you want them)
-
-* Add an example connection manager that has dummy StreamedMedia channels
-
-* Add an example connection manager that has dummy ContactList channels
- vaguely resembling the XMPP roster
-
-* Update to telepathy-spec 0.17.21 (adding
- TP_CHANNEL_GROUP_FLAG_MESSAGE_DEPART and
- TP_CHANNEL_MEDIA_CAPABILITY_NAT_TRAVERSAL_ICE_UDP)
-
-Fixes:
-
-* fd.o #20646: in TpChannel, when adding contacts to one of the Group sets,
- remove them from both of the others
-
-* Use AM_PATH_PYTHON to detect the Python version
-
-* In TpGroupMixin, let implementations allow the self-handle to be removed
- regardless of whether the CAN_REMOVE flag is set. This is meant to be how
- you remove yourself gracefully from a chatroom or streamed media call.
-
-* fd.o #20165: fix a use-after-free in tp_base_connection_register() that
- causes connection managers to assert if they have not already called
- tp_dbus_daemon_dup() or tp_run_connection_manager() (regression in 0.7.26
- which broke the telepathy-qt4 regression tests)
-
-* Fix some memory leaks when making TpContact objects, when holding handles in
- TpContactsMixin, when filling contact attributes in TpPresenceMixin,
- when setting simple presence, and in the regression tests
-
-* Update the valgrind suppressions file to cope with new telepathy-glib code,
- GTest, and glibc 2.9
-
-* Fix compilation with gtkdoc 1.11, which is stricter about the contents of
- Since: annotations, and parses more comments
-
-telepathy-glib 0.7.26 (2009-02-16)
-==================================
-
-The "Leffe Radieuse" release.
-
-Enhancements:
-
-* Add tp_connection_manager_call_when_ready()
-
-* When constructing TpConnectionManager, if the .manager file is missing
- or can't be read, always try to activate the connection manager (in
- practice, this is what's wanted)
-
-* fd.o #18291: when listing connection managers, wait for them to all be ready
-
-* fd.o #18056: add method-based accessors for TpConnectionManager members
-
-* fd.o #17519: track the Connection's SelfHandle property in TpConnection
-
-* Add tp_dbus_daemon_dup(), convenient API to share a starter-bus connection
-
-* Generate GTypes for arrays of mappings, and improve use of the
- type-generation functions
-
-* fd.o #19907: Add tp_intset_new_containing(), a convenient factory for sets
- with exactly one member
-
-Deprecations:
-
-* Deprecate tp_get_bus_proxy()
-
-Fixes:
-
-* Reduce our reliance on making a DBusGProxy for the dbus-daemon (working
- towards avoiding overly-broad NameOwnerChanged matches)
-
-* fd.o #18832 (partially addressed): document that tp_get_bus() can call
- exit() and why, and discourage it in processes that aren't totally reliant
- on D-Bus
-
-* fd.o #18207: reliably emit TpConnectionManager::got-info signal (although
- tp_connection_manager_call_when_ready() should be used instead)
-
-* Fix some assertion failures in TpConnectionManager when .manager files
- contain surprising types
-
-* fd.o #19054: Parse all currently supported types in .manager files
-
-* fd.o #20096: don't consider InvalidHandle to be fatal for
- tp_connection_get_contacts_by_id (spec 0.17.18 compliance)
-
-Miscellaneous:
-
-* Add regression test coverage for TpConnectionManager
-
-telepathy-glib 0.7.25 (2009-01-30)
-==================================
-
-The "Paradise Lost" release.
-
-Fixes:
-
-* fd.o #17588: don't break ABI if errors are re-ordered in a future spec
- version
-
-* fd.o #19688: don't assert when getting contacts by ID if none of the
- identifiers supplied are valid
-
-* TpPresenceMixin: don't allow setting statuses that are flagged as not
- settable on the user themselves
-
-* TpPresenceMixin: never allow statuses of type OFFLINE, UNKNOWN or ERROR to
- be set on the user themselves, and warn if the connection manager got this
- wrong
-
-* Fix a memory leak in tp_presence_mixin_get_statuses() (sorry Jonathon,
- your patch got lost during the release process...)
-
-telepathy-glib 0.7.24 (2009-01-28)
-==================================
-
-The "Divide By Cucumber Error" release.
-
-API changes:
-
-* When a TpConnection is invalidated due to disconnection, the error will now
- be chosen from the TP_ERRORS domain in most cases. Previously, the
- TP_ERROR_DISCONNECTED domain was used. This change is necessary to support
- the extensible error reporting introduced in spec 0.17.19.
-
-Enhancements:
-
-* Update to telepathy-spec 0.17.19
- - Many new errors in the TP_ERRORS domain
- - Connection.ConnectionError signal for extensible error reporting
-
-* Add a client binding for the extensible error reporting provided
- by the ConnectionError signal
-
-* Use a simple Python implementation of XInclude, rather than xsltproc, for
- easier Windows porting
-
-Fixes:
-
-* Add File Transfer to the documentation
-
-telepathy-glib 0.7.23 (2009-01-20)
-==================================
-
-The "new in version 0.7.1, and allegedly also in 0.7.21" release.
-
-Enhancements:
-
-* Updated to spec version 0.17.18
- - Added the File Transfer channel type
- - Added TpRichPresenceAccessControlType and
- TP_STRUCT_TYPE_RICH_PRESENCE_ACCESS_CONTROL
- - RequestHandles raises NotImplemented for bad handle types or InvalidHandle
- for bad identifiers (fd.o #19609)
- - MediaStreamHandler has a CodecsUpdated method
- - Methods automatically generated by telepathy-glib now have names
- for all "out" arguments, which should make the documentation easier to use
-
-* Use tp:name-for-bindings to construct the C name for D-Bus methods etc.,
- which will result in better C function naming for future D-Bus interfaces
- like DBusTube
-
-Fixes:
-
-* Remove symbols from 0.7.21.abi that were already in 0.7.1.abi (GNU ld
- seems to respond by giving them the older version, so no harm was done
- to the ABI, but it broke the Debian packages)
-
-* Make make-version-script.py fail if that ever happens again
-
-* Annotate things added in 0.7.21 with the correct "Since:" indicator
-
-* Correct the documentation for tp_list_connection_names()
-
-telepathy-glib 0.7.22 (2009-01-13)
-==================================
-
-The "TP_STRUCT_TYPE_BROWN_PAPER_BAG" release.
-
-Fixes:
-
-* Accept message=NULL in tp_group_mixin_change_members, as documented and true
- in the past, rather than crashing.
-
-telepathy-glib 0.7.21 (2009-01-12)
-==================================
-
-The "TP_HASH_TYPE_PINT_HOBGOBLIN_MOUTH_MAP" release.
-
-Enhancements:
-
-* Updated to spec version 0.17.17
- - Added TP_HASH_TYPE_HANDLE_IDENTIFIER_MAP and
- TP_HASH_TYPE_MESSAGE_PART_CONTENT_MAP
-
-* (Finally) merged TpMessageMixin, which can be used in place of TpTextMixin to
- implement the Messages interface on Text channels.
-
-* The examples have been made more exemplary, using TpChannelManager in place
- of TpChannelFactoryIface, implementing Destroyable and respawning 1-1 text
- channels which are closed with pending messages.
- (fd.o #17632)
-
-* Added a TP_COMPILER_WARNINGS macro to simplify choosing compiler warnings in
- configure.ac, and forked a version of AS_COMPILER_FLAG that supports C++ so
- that TP_COMPILER_WARNINGS can be used for C++ projects (such as
- telepathy-qt4). Other projects using telepathy-glib's warnings might want to
- copy m4/tp-compiler-*.m4 and use TP_COMPILER_WARNINGS.
-
-* Added support to TpGroupMixin for emitting the MembersChangedDetailed signal
- (fd.o #19050 and #19052), and to TpChannel for listening to it when possible
- (fd.o #19051).
-
-* Added tp_channel_get_identifier
-
-* Added support for parsing the dbus-property CM parameter flag (introduced in
- spec 0.17.16) from .manager files (fd.o #19053).
-
-Fixes:
-
-* Various Win32 portability fixes (from Sunil Mohan Adapa on fd.o #19461).
-
-* fd.o #19101: tp_connection_get_contacts_by_id() crashes
-
-telepathy-glib 0.7.20 (2008-12-14)
-==================================
-
-The "xfs_freeze stole the night" release.
-
-Enhancements:
-
-* Updated to spec version 0.17.16
- - Generate code for the Messages interface, which is now undrafted.
-
-Fixes:
-
-* fd.o #18845: don't throw a critical error from TpConnection if the
- corresponding CM falls off the bus.
-
-* fd.o #18926: avoid using a non-top-level GLib header
-
-telepathy-glib 0.7.19 (2008-12-01)
-==================================
-
-The "fast path" release.
-
-Enhancements:
-
-* TpContact now has a fast path using the Contacts interface to reduce
- D-Bus round-trips, if supported
-
-* tp_connection_get_contact_attributes integrates the Contacts interface
- with TpConnection's handle reference tracking at a lower level
-
-* TpChannel now tracks its immutable properties (as provided by
- Requests.NewChannels, Requests.CreateChannel and Requests.EnsureChannel),
- can be constructed from a dictionary of immutable properties
- (tp_channel_new_from_properties), and has a fast path using GetAll to reduce
- round trips (if supported); when constructed from a dictionary of immutable
- properties, non-Group channels should become 'ready' in a single round-trip
- (fd.o #17427)
-
-* Only use the Properties mixin in there are properties defined
-
-Fixes:
-
-* fd.o #15092: mixins in a superclass should now work correctly in subclasses
-
-* fd.o #18151: tp_base_connection_dispose asserts if there are two connections to the same account
-
-telepathy-glib 0.7.18 (2008-11-03)
-==================================
-
-The "320 GB" release.
-
-Enhancements:
-
-* Update to spec 0.17.14
- * test, and generate code for, the Destroyable interface
- * add support for the SCROLLBACK and RESCUED message flags in Text
- * add tp_text_mixin_set_rescued(), for CMs to call when respawning a channel,
- and tp_text_mixin_receive_with_flags(), for CMs to call when receiving
- scrollback messages
- * update echo example CM's Text support to spec 0.17.14
- * CreateChannel etc. return before NewChannels, which is emitted before
- NewChannel
-
-* Add TpContact, an object representing a contact, with inspection of various
- attributes (e.g. alias, avatar token and SimplePresence)
-
-Fixes:
-
-* In TpContactsMixin, always return info from interface TP_IFACE_CONNECTION
- even if the client didn't ask for it, since the spec says we should
-
-* Add a simple regression test for TpContactsMixin
-
-* Use unsigned int (rather than gboolean, which is signed!) for bitfields
-
-* Fix a memory leak when a TpChannel with the Group interface is freed
-
-* Fix a memory leak in tp_connection_unref_handles when no handles are released
-
-* Fix some memory leaks in the regression tests
-
-* Re-enable the coding style check and fix various things it complained about
-
-telepathy-glib 0.7.17 (2008-10-14)
-==================================
-
-The "inexplicable bonus pizza" release.
-
-Enhancements:
-
-* Updated to spec 0.17.13, which adds Requested, InitiatorHandle and
- InitiatorID properties to Channel
-
-* Updated two example CMs (echo and channelspecific) to spec 0.17.13 too
-
-* Added handle reference-counting helpers, which should be used instead
- of using the HoldHandles, RequestHandles and ReleaseHandles D-Bus API
- directly
-
-* Added C accessors for TpProxy's read-only properties, and for
- TpConnection's connection-ready property
-
-* Added some infrastructure for test coverage analysis using lcov
-
-* Moved some of the release/checking machinery to tools/telepathy.am
- for easy pasting into other Telepathy projects
-
-* The first time TP_ERRORS is used, the error domain is now automatically
- registered with dbus-glib
-
-* Added sanity checks (g_return_if_fail/g_critical) to TpConnection,
- TpProxy, TpDBusDaemon and tp_dbus_check_* public API
-
-Fixes:
-
-* tp_handle_is_valid and tp_handles_are_valid raise InvalidHandle on failure,
- not InvalidArgument (numerous methods in telepathy-spec require
- InvalidHandle to be raised, so this should make most CMs more
- spec-compliant)
-
-* The test and example CMs raise NotAvailable on syntactically incorrect
- strings, rather than InvalidArgument (which is not spec-compliant)
-
-* The example valgrind suppressions file now works if libdbus was not
- installed in /usr, or if glibc is version 2.7
-
-* fd.o #17502: fixed documentation of the #include for TpDBusPropertiesMixin
-
-* Fixed a memory leak in TpContactsMixin
-
-telepathy-glib 0.7.16 (2008-09-26)
-==================================
-
-The "could you say that again? I was looking at that bee" release.
-
-Dependencies:
-
-* To use --enable-gtk-doc you must now have at least gtkdoc 1.10
-
-Enhancements:
-
-* Updated to spec 0.17.12, mainly featuring EnsureChannel
-
-* We now support EnsureChannel on the Requests interface - to implement this,
- put a suitable function pointer in TpChannelManagerIface::ensure_channel
-
-* Channel factories' RequestChannel implementations no longer need to
- validate handles - TpBaseConnection now does this automatically
-
-* Added a function to compare presence types in order of "availability"
-
-Fixes:
-
-* The gtkdoc now documents GInterfaces' signals and properties (fd.o #16995,
- fd.o #17308)
-
-* TpBaseConnection::self_handle is unreffed and cleared slightly later,
- for the benefit of channel managers that want to use it in their
- status-changed(Disconnected) callback
-
-* Fixed a compiler warning on platforms with daemon(3) in their libc
-
-* TpChannelManager can no longer be crashed by asking for unsupported
- handle types
-
-telepathy-glib 0.7.15 (2008-09-18)
-==================================
-
-The "plumbing" release.
-
-Dependencies:
-
-* GLib and GObject must be at least version 2.16 (this was accidentally the
- case in 0.7.14 too, but the dependency is now official). (fd.o #17213)
-
-Deprecations:
-
-* TpBaseConnection implementations should use the new method
- tp_base_connection_set_self_handle instead of setting the self_handle member
- directly. To comply with spec 0.17.10, if the self-handle changes after the
- status becomes CONNECTED, tp_base_connection_set_self_handle *must* be used.
-
-Enhancements:
-
-* Updated to specification 0.17.10, which includes the SelfHandleChanged signal
- and SelfHandle property...
-
-* ... and then to specification 0.17.11, which includes the stable Requests
- interface with the CreateChannel method (but not EnsureChannel, which is
- planned for a future spec.).
-
-* Added support for the Requests interface to TpBaseConnection, using the new
- interfaces TpChannelManager and TpExportableChannel (which are intended to
- replace TpChannelFactoryIface and TpChannelIface).
-
-* Added some utility functions: tp_dbus_properties_mixin_make_properties_hash,
- tp_strv_contains
-
-* with-session-bus.sh (used for the tests) optionally records dbus-monitor
- output
-
-* telepathy-glib-uninstalled.pc is generated in source builds. It's now
- easier to compile dependent projects against an uninstalled copy of
- telepathy-glib >= 0.7.15, like this:
-
- PKG_CONFIG_PATH=$HOME/src/telepathy-glib/telepathy-glib ./autogen.sh
-
- (if $HOME/src/telepathy-glib is the directory containing this file)
-
-Fixes:
-
-* TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED no longer causes compiler warnings
- when used from a C++ source file
-
-* glib-client-gen.py generates correct code for 64-bit unsigned integers
-
-Release notes for projects using code generation:
-
-* If you generate client-side code, update glib-client-gen.py to avoid wrong
- code generation for unsigned 64-bit integer arguments. This will cause your
- project to require telepathy-glib >= 0.7.3
-
-* If you use a copy of with-session-bus.sh for regression tests, consider
- updating it to add support for logging dbus-monitor
-
-telepathy-glib 0.7.14 (2008-08-19)
-==================================
-
-The "M'era Luna" release.
-
-Enhancements:
-
-* Updated to specification 0.17.9
- - Connection.Interface.Contacts interface ("the inspectotron"), which allows
- mass contact-handle holding and inspection in a single round-trip
- - Channel.TargetID property, for further round-trip reduction
-
-* Added TpContactsMixin, a generic implementation of the Contacts interface
-
-* Moved source code control from darcs to git (see README for details)
-
-* Added tp_connection_get_status() convenience accessor for status and
- status-reason properties
-
-* Altered tp_debug_divert_messages() to support a "+" prefix to filenames,
- which changes the mode from truncate to append: you can now set something
- like GABBLE_LOGFILE="+gabble.log" to append to an existing log
-
-* Updated AUTHORS
-
-telepathy-glib 0.7.13 (2008-07-29)
-==================================
-
-The "presence made easy" release.
-
-Enhancements:
-
-* TpPresenceMixin implements the new SimplePresence interface
-
-* The spec text and doc-generator.xsl have been updated
-
-* The coding-style checks have been removed
-
-* A couple of supporting functions for Requests API development have
- been added (tp_text_mixin_has_pending_messages and
- tp_dbus_properties_mixin_get)
-
-Release notes for projects using code generation:
-
-* We now ship the more pedantic doc-generator.xsl from telepathy-spec 0.17.8:
- - you'll probably need to clean up your spec markup!
- - set the allow-undefined-interfaces XSLT parameter to a true value (e.g.
- run xsltproc with --param allow-undefined-interfaces "true()") if you are
- compiling documentation for interfaces that are not self-contained
- (e.g. Telepathy extensions that reference the main Telepathy spec)
-
-* If you're trying to use Telepathy coding style, upgrading the coding-style
- checks is recommended, but might require you to make code changes
-
-telepathy-glib 0.7.12 (2008-07-21)
-==================================
-
-The "Channel.Interface.Useful" release.
-
-Enhancements:
-
-* TpChannel and TpConnection can be subclassed (fd.o #14828, #14829)
-
-* TpChannel has various convenience methods like tp_channel_get_channel_type(),
- which can be used as an alternative to its GObject properties
-
-* Internally, TpChannel tries to use D-Bus core Properties (the GetAll
- method) to reduce round-trips; if that fails, it will automatically fall
- back to a series of normal method calls
-
-* TpChannel tracks the Group interface automatically (fd.o #14180)
-
-* tp_asv_size() has been added to the a{sv} convenience API, which now has
- its own file in the documentation
-
-Fixes:
-
-* For the moment, TpDBusPropertiesMixin raises Telepathy errors rather than
- D-Bus core errors on failure, due to fd.o #16776 in dbus-glib causing an
- assertion when DBUS_GERROR errors are raised
-
-* TpConnectionManager no longer causes a crash if destroyed before it has
- read the .manager file (fd.o #16774, thanks to Sunil Mohan Adapa for the
- patch)
-
-Dependencies:
-
-* We no longer support automake 1.8.x, since even Maemo has had 1.9 for a
- while. We don't yet use any automake 1.9 features, but we will no longer
- test with 1.8 unless someone explains to me why a 4 year old version is
- still relevant :-)
-
-telepathy-glib 0.7.11 (2008-07-02)
-==================================
-
-The "design is hard" release.
-
-This is mainly a bugfix release.
-
-Fixes:
-
-* fd.o #16307: in TpConnection, don't assert when a connection goes CONNECTED
- while a GetStatus call is pending
-
-* In TpDBusPropertiesMixin: return properly if Get, Set or GetAll are called
- on nonexistent interfaces or properties; if the wrong type is passed to Set,
- coerce it to the right type (if possible) and actually use the right type;
- and if the coercion fails, don't leak memory
-
-* In libglibcodegen (code generation), use the right GType for arrays of
- object-path
-
-Enhancements:
-
-* Use Python rather than XSLT for code generation, for improved maintainability
-
-Release notes for projects using code generation:
-
-* All the XSLT (except doc-generator.xsl and identity.xsl) has been rewritten
- in Python. It should produce identical results, but be careful when updating!
-
-* You must update libglibcodegen to this version if there are arrays of
- object-path in your API, otherwise it just won't work
-
-telepathy-glib 0.7.10 (2008-06-06)
-==================================
-
-The "properties everywhere" release.
-
-Again, this version mainly contains infrastructure to support future APIs,
-like the planned Requests API.
-
-Enhancements:
-
-* Update to telepathy-spec 0.17.7
- - Channel gained immutable/read-only ChannelType, TargetHandleType,
- TargetHandle and Interfaces properties
-
-* TpGroupMixin now supports the Group properties introduced in the previous
- version
-
-* Added an example connection manager with channel-specific handles in
- chatrooms
-
-telepathy-glib 0.7.9 (2008-05-30)
-=================================
-
-The "scaffolding" release.
-
-This version mostly contains infrastructure to support APIs that are coming
-soon, but haven't got through the review process yet.
-
-Enhancements:
-
-* Update to telepathy-spec 0.17.5
- - RoomList gained a read-only Server property
- - Text gained TP_CHANNEL_TEXT_MESSAGE_FLAG_NON_TEXT_CONTENT,
- TP_CHANNEL_TEXT_MESSAGE_TYPE_DELIVERY_REPORT to support the future
- Messages and DeliveryReporting interfaces
-
-* Update to telepathy-spec 0.17.6
- - Group properties (but the group mixin does not yet implement them)
- - Group HandleOwnersChanged, SelfHandleChanged
- - TP_HASH_TYPE_CHANNEL_OWNER_MAP
-
-* New functions tp_asv_get_uint32() etc. to make it easier to use a{sv}
- hash tables (implemented in dbus-glib as a GHashTable of gchar * => GValue *)
-
-* Enhance TpDBusPropertiesMixin so that mixins can provide properties more
- easily
-
-* Start porting the remaining XSLT to Python for better maintainability
-
-Fixes:
-
-* TpProxy: Avoid a misleading debug message every time a pending call
- completes, and probably fix detection of crashing services
-
-* tp_dbus_check_valid_interface_name: correctly detect that a name with a
- dot followed by a digit is invalid
-
-* Add a Valgrind suppression for SELinux-related ld.so initialization (not our
- problem)
-
-Release notes for projects using code-generation:
-
-* When you update tools copied from telepathy-glib, be aware that
- libglibcodegen.py now depends on libtpcodegen.py, and that some of the
- formerly-XSLT tools have been replaced by Python versions
-
-telepathy-glib 0.7.8 (2008-05-09)
-=================================
-
-The "Hold, unheld" release
-
-Enhancements:
-
-* Update to telepathy-spec 0.17.4
- - add Hold API to code-generation
-
-Fixes:
-
-* Make coding-style check less fragile
-
-Recommended updates for projects using check-coding-style.mk:
-
-* Update check-coding-style.mk
-
-* In every Makefile where check-coding-style.mk is used, make check-local
- depend on check-coding-style (this is no longer done automatically)
-
-telepathy-glib 0.7.7 (2008-05-02)
-=================================
-
-The "Old Trip" release.
-
-API changes:
-
-* It is an error to pass non-NULL user_data, weak_object or destroy arguments
- when making an asynchronous method call with callback == NULL (i.e.
- ignoring the reply) - doing this would make no sense
-
-Enhancements:
-
-* Implement tp_connection_call_when_ready, tp_channel_call_when_ready -
- fully async variants of the existing run_when_ready API (fd.o #15300)
-
-* Documentation: divide up the service-side Channel interfaces by topic,
- in the same way the client-side ones were already divided up
-
-* TpTextMixin: drop the futile attempt to limit memory consumption. We were
- doing it wrong, and a typical connection manager has so many ways it can
- be induced to consume memory that trying to guard against this particular
- case by truncating or dropping messages seems likely to cause more problems
- than it fixes.
-
-* TpTextMixin: save a malloc/free cycle in GetMessageTypes
-
-* TpGroupMixin: don't emit GroupFlagsChanged(0, 0)
-
-* Log a message when disconnected from the D-Bus session bus
-
-* Improve ABI-checking functionality so symbols only have to be whitelisted
- just before a release
-
-Fixes:
-
-* TpBaseConnection: don't return from Disconnect() until disconnection has
- fully completed (fd.o #15796)
-
-* libglibcodegen.py: generate correct bindings for arrays of object-path (ao)
-
-* glib-client-gen.py: cope correctly with Unicode in the spec
-
-* doc-generator.xsl: update from telepathy-spec to cope with arrays of mappings
-
-* When a channel's connection becomes invalidated, don't warn if the
- resulting invalidation causes the channel to be freed (fd.o #15644)
-
-* In tp_handle_lookup() on a dynamic handle repository, if the ID is valid
- but there is no handle, raise the error NotAvailable, instead of returning
- 0 with no error set (fd.o #15387)
-
-* When asynchronous method calls are made on an unsupported interface, call
- the user-supplied destroy() callback on the user_data (fd.o #15530)
-
-* TpTextMixin: fix a memory leak in ListPendingMessages
-
-* Use automake 1.8 if available, to verify that we can still build on such
- an old version
-
-* When running under valgrind with the recommended suppressions, don't
- complain about libc dlopen initialization caused by the handle-leak debug
- code
-
-Recommended updates for projects using code-generation:
-
-* Update libglibcodegen.py to avoid a crash if arrays of object-path appear
- in your API in future
-
-* Update glib-client-gen.py to avoid fd.o #15530; this will cause your project
- to require telepathy-glib >= 0.7.3
-
-telepathy-glib 0.7.6 (2008-04-03)
-=================================
-
-The "hold the assertions" release.
-
-API changes:
-
-* API was added to fix fd.o #15325. Projects that add extension interfaces
- to TpChannel or TpConnection might suffer from assertion failures if those
- interfaces are later added to telepathy-glib, unless they follow the
- recommendations below. Projects that do not use the telepathy-glib code
- generation tools are unaffected.
-
-* Related to the above, extending TpDBusDaemon, TpMediaStreamHandler,
- TpMediaSessionHandler and TpConnectionManager is officially not supported
- at this time.
-
-Enhancements:
-
-* Updated to specification 0.17.3
- - supports the CallState interface, for receiving notifications of a
- remote contact or device's state (currently supported states are: ringing,
- queued, placed us on hold)
- - MediaStreamHandler supports some new Hold-related API
- - the Hold interface is *not* yet supported, use private code-generation
- (as seen in telepathy-sofiasip) for now
-
-Fixes:
-
-* Doesn't assert in client code when a connection's GetInterfaces method fails
- (fd.o #15306)
-
-* The build process works on platforms without -Wl,-O1 and
- -Wl,--version-script, such as Mac OS X (fd.o #15026)
-
-* test-handle-set now runs under a temporary session bus, so the tests can work
- in platforms without working D-Bus autolaunch
-
-* Code generation uses G_GNUC_UNUSED where necessary, so you can use the
- generated code in projects with stricter warning flags than telepathy-glib
- itself
-
-* A couple of unterminated argument lists when initializing the allowed
- message types for the text mixin have been fixed
-
-* glib-client-gen.py optionally inserts a guard against assertion failures
- caused by a local extension overriding an interface that is also now provided
- by telepathy-glib (fd.o #15325)
-
-* glib-client-gen.py has a mechanism to allow its output to be made
- backwards-compatible: specify --tp-proxy-api=x.y.z where x.y.z is the oldest
- version of telepathy-glib you check for in configure.ac (it must be at
- least 0.7.6)
-
-Recommended updates for projects using telepathy-glib code generation:
-
-* Update glib-client-gen.py from telepathy-glib, and invoke it with
- the extra argument "--tp-proxy-api=0.7.6", to fix #15325 (this will make
- the generated code require telepathy-glib 0.7.6)
-
-* Before calling tp_proxy_or_subclass_hook_on_interface_add for an existing
- class, call tp_proxy_init_known_interfaces,
- tp_connection_init_known_interfaces or tp_channel_init_known_interfaces.
-
-telepathy-glib 0.7.5 (2008-03-07)
-=================================
-
-Enhancements:
-
-* Updated to specification 0.17.2
- - GType-generating functions for Media_Session_Handler_Info
- - Added TP_CONN_MGR_PARAM_FLAG_SECRET
-
-Fixes:
-
-* No longer crashes if a proxy is invalidated while still invoking signal
- callbacks (fd.o #14854)
-
-* Compilation now works on architectures with function descriptors, like ppc64
- (fd.o #14852, thanks Brian Pepple)
-
-* TpChannel no longer crashes if GetInterfaces() returns an error or an
- empty list (fd.o #14855)
-
-* Linking examples no longer fails in environments where .la files exist for
- system libraries
-
-telepathy-glib 0.7.4 (2008-03-04)
-=================================
-
-Fixes:
-
-* Refactoring and life-cycle fixes in TpProxy, including some assertions
- during method-call and signal-connection cancellation (fd.o #14750; fixes a
- crash in development versions of Mission Control)
-
-* Maps "_" back to "-" in protocol names seen in bus names (fd.o #14667;
- fixes telepathy-inspector 0.5.1 not displaying Salut connections)
-
-* Does not leak the GError when connecting to signals on an unsupported
- interface (fd.o #14746)
-
-* Builds with more warnings by default, for additional strictness
-
-* Improvements to example client code:
- - make example_cli_init() safe to call multiple times
- - generate signals-marshal.list in a way that avoids more gcc warnings
-
-Recommended updates for projects using telepathy-glib code generation:
-
-* Update glib-client-gen.py from telepathy-glib to fix #14746 (this will make
- the generated code require telepathy-glib 0.7.3)
-* Consider updating *_cli_init() and extensions/Makefile.am to resemble the
- examples
-
-telepathy-glib 0.7.3 (2008-02-20)
-=================================
-
-Requirements:
-
-* pkg-config 0.21 is now required
-
-* gtkdoc 1.8 is recommended
-
-Enhancements:
-
-* Supports org.freedesktop.DBus.Properties with a mixin for services, and
- extensions to auto-generated code
-
-Fixes:
-
-* Fixed a crash that could occur when pending calls on otherwise unreferenced
- proxies are cancelled, e.g. during teardown in telepathy-stream-engine
- (fd.o #14576)
-
-* Correct client-side bindings are generated for methods that return a variant
- (e.g. o.fd.DBus.Properties.Get) fixing potential crashes in clients
-
-* tp_dbus_check_valid_object_path allows "/" and disallows "//", not the
- reverse
-
-* Partially works around some gtkdoc 1.7 bugs (if your gtkdoc is 1.7 you'll
- still lose the "Telepathy protocol enumerations" section)
-
-* Uses pkg-config's Requires.private feature to reduce shared library
- interdependencies
-
-telepathy-glib 0.7.2 (2008-02-11)
-=================================
-
-* Fixed incorrect GValue code that caused Empathy to assert on
- Room -> Join New...
-
-* Added support for the D-Bus core Properties, Introspect and Peer interfaces
-
-telepathy-glib 0.7.1 (2008-01-04)
-=================================
-
-This is a major feature release, adding client-side code which continues the
-process of making libtelepathy obsolete.
-
-* Implements specification 0.17.1
- - it is a fatal error for TpBaseConnectionManagerClass::cm_dbus_name not to
- conform to the specification (briefly: it must match
- /[A-Za-z_][A-Za-z0-9_]+/)
- - connections cannot be opened for protocols not matching
- /[A-Za-z-][A-Za-z0-9-]+/
-
-* Initial client-side code added:
- - TpProxy, a much more capable version of DBusGProxy (it more closely
- resembles a dbus-python ProxyObject, with one object per connection,
- channel etc. rather than one per interface)
- - auto-generation machinery for client call wrappers (namespaced tp_cli_*)
- - TpDBusDaemon, a TpProxy subclass to talk to the bus daemon
- - TpChannel, a channel (replaces libtelepathy's TpChan)
- - TpConnection, a connection (replaces libtelepathy's TpConn)
- - TpConnectionManager, a connection manager (replaces libtelepathy's
- TpConnMgr)
- - TpMediaStreamHandler and TpMediaSessionHandler, media signalling helpers
- - Correct algorithms for listing connection managers, listing connections,
- and reading .manager files (as documented in the 0.17.1 spec)
-
-* Examples extended:
- - various simple client examples
- - an "echo" connection manager
- - an extended connection manager and client (implementing a hypothetical
- Hats interface), to illustrate how to support experimental or extension
- interfaces in services and clients
-
-* Miscellaneous:
- - tp_debug_divert_messages (adapted from Gabble)
- - tp_debug_timestamped_log_handler (adapted from Gabble)
- - tp_cm_param_setter_offset now supports byte-array params
-
-* Versioned symbols
- - versions are of the form TELEPATHY_GLIB_x.y.z
- - unreleased development builds use versions containing _UNRELEASED
- to force relinking against a proper version
-
-telepathy-glib 0.7.0 (2007-11-22)
-=================================
-
-This is the first release from the 0.7.0 development branch, and
-prepares the way for the client-side code I'm going to be merging soon.
-
-* Enums etc. updated to specification 0.17.0
-* Improved support for connection managers whose parameters aren't known
- at compile time (*coughhazecough* :-)
-* Build system refactoring to make it less weird
-* GType-generating functions and macros in gtypes.h cache the results of calls
- to dbus-glib type lookup functions, and give data types convenient names
-* Functions and macros to generate GQuarks for interface names (which will
- be used extensively by client code in future)
-* The beginning of an examples/ directory, containing the simplest possible
- example connection manager (it doesn't support any protocols)
-* Dependencies increased to libdbus 0.93, dbus-glib 0.73, glib 2.10
diff --git a/autogen.sh b/autogen.sh
index f92b907d9..939aa7d8e 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -5,13 +5,14 @@ gtkdocize
if test -n "$AUTOMAKE"; then
: # don't override an explicit user request
-elif automake-1.9 --version >/dev/null 2>/dev/null && \
- aclocal-1.9 --version >/dev/null 2>/dev/null; then
- # If we have automake-1.9, use it. This helps to ensure that our build
- # system doesn't accidentally grow automake-1.10 dependencies.
- AUTOMAKE=automake-1.9
+elif automake-1.11 --version >/dev/null 2>/dev/null && \
+ aclocal-1.11 --version >/dev/null 2>/dev/null; then
+ # If we have automake-1.11, use it. This is the oldest version (=> least
+ # likely to introduce undeclared dependencies) that will give us
+ # --enable-silent-rules support.
+ AUTOMAKE=automake-1.11
export AUTOMAKE
- ACLOCAL=aclocal-1.9
+ ACLOCAL=aclocal-1.11
export ACLOCAL
fi
@@ -28,15 +29,6 @@ for arg in $*; do
esac
done
-# Workaround for gtk-doc + shave + libtool 1.x
-# See http://git.lespiau.name/cgit/shave/tree/README#n83
-sed -e 's#) --mode=compile#) --tag=CC --mode=compile#' gtk-doc.make \
- > gtk-doc.temp \
- && mv gtk-doc.temp gtk-doc.make
-sed -e 's#) --mode=link#) --tag=CC --mode=link#' gtk-doc.make \
- > gtk-doc.temp \
- && mv gtk-doc.temp gtk-doc.make
-
if test $run_configure = true; then
./configure "$@"
fi
diff --git a/configure.ac b/configure.ac
index 8c84fd039..24b055720 100644
--- a/configure.ac
+++ b/configure.ac
@@ -10,16 +10,25 @@ AC_PREREQ([2.59])
# set nano_version to 1
m4_define([tp_glib_major_version], [0])
-m4_define([tp_glib_minor_version], [8])
+m4_define([tp_glib_minor_version], [9])
m4_define([tp_glib_micro_version], [0])
m4_define([tp_glib_nano_version], [1])
-# Do not add API/ABI in this branch (which means current and age stay at 30).
-# If library source has changed since last release, increment revision.
-
-m4_define([tp_glib_lt_current], [30])
-m4_define([tp_glib_lt_revision], [1])
-m4_define([tp_glib_lt_age], [30])
+# If library source has changed since last release, increment revision
+# If interfaces have been added, removed or changed since last release,
+# increment current and set revision to 0
+# If interfaces have been added since last release, increment age
+# If interfaces have been removed since last release, set age to 0
+#
+# If interfaces have been added, release builds will fail unless you add a new
+# file like telepathy-glib/versions/0.7.3.abi to add them to the official ABI.
+# This also forces binaries built against devel versions to be rebuilt
+# (we don't guarantee that we won't add ABI then remove it again, if it was
+# never seen in a release).
+
+m4_define([tp_glib_lt_current], [31])
+m4_define([tp_glib_lt_revision], [0])
+m4_define([tp_glib_lt_age], [31])
# Some magic
m4_define([tp_glib_base_version],
@@ -36,6 +45,8 @@ AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([1.9 -Wno-portability])
AM_CONFIG_HEADER(config.h)
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES])
+
dnl check for tools
AC_PROG_CC
AC_PROG_CC_STDC
@@ -139,8 +150,8 @@ dnl (srcdir != builddir)
AM_CONDITIONAL([OUT_OF_TREE_BUILD], [test "z$ac_srcdir" != z.])
dnl Check for Glib
-PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.16, gobject-2.0 >= 2.16])
-
+PKG_CHECK_MODULES(GLIB,
+ [glib-2.0 >= 2.20, gobject-2.0 >= 2.20, gio-2.0 >= 2.20])
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
@@ -185,8 +196,6 @@ if test -z "$NM"; then
fi
AM_CONDITIONAL([HAVE_LD_VERSION_SCRIPT], [test $HAVE_LD_VERSION_SCRIPT = yes])
-SHAVE_INIT(.)
-
AC_OUTPUT( Makefile \
docs/Makefile \
docs/reference/Makefile \
@@ -210,7 +219,5 @@ AC_OUTPUT( Makefile \
tests/dbus/Makefile \
tests/tools/Makefile \
tools/Makefile \
- m4/Makefile \
- shave \
- shave-libtool
+ m4/Makefile
)
diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt
index 34de9a7a1..2c1df5eb2 100644
--- a/docs/reference/telepathy-glib-sections.txt
+++ b/docs/reference/telepathy-glib-sections.txt
@@ -3027,6 +3027,49 @@ TpAccount
TpAccountClass
tp_account_new
tp_account_init_known_interfaces
+tp_account_parse_object_path
+tp_account_get_connection
+tp_account_ensure_connection
+tp_account_get_display_name
+tp_account_get_connection_manager
+tp_account_get_protocol
+tp_account_get_icon_name
+tp_account_set_enabled_async
+tp_account_set_enabled_finish
+tp_account_reconnect_async
+tp_account_reconnect_finish
+tp_account_is_enabled
+tp_account_is_valid
+tp_account_update_parameters_async
+tp_account_update_parameters_finish
+tp_account_remove_async
+tp_account_remove_finish
+tp_account_set_display_name_async
+tp_account_set_display_name_finish
+tp_account_set_icon_name_async
+tp_account_set_icon_name_finish
+tp_account_request_presence_async
+tp_account_request_presence_finish
+tp_account_get_connect_automatically
+tp_account_set_connect_automatically_async
+tp_account_set_connect_automatically_finish
+tp_account_get_has_been_online
+tp_account_get_connection_status
+tp_account_get_current_presence
+tp_account_get_requested_presence
+tp_account_get_parameters
+tp_account_get_nickname
+tp_account_set_nickname_async
+tp_account_set_nickname_finish
+tp_account_get_avatar_async
+tp_account_get_avatar_finish
+<SUBSECTION>
+TP_ACCOUNT_FEATURE_CORE
+tp_account_is_prepared
+tp_account_prepare_async
+tp_account_prepare_finish
+<SUBSECTION Private>
+tp_account_get_feature_quark_core
<SUBSECTION>
tp_cli_account_callback_for_reconnect
tp_cli_account_call_reconnect
@@ -3061,6 +3104,21 @@ TpAccountManager
TpAccountManagerClass
tp_account_manager_new
tp_account_manager_init_known_interfaces
+tp_account_manager_dup
+tp_account_manager_create_account_async
+tp_account_manager_create_account_finish
+tp_account_manager_ensure_account
+tp_account_manager_get_valid_accounts
+tp_account_manager_get_most_available_presence
+tp_account_manager_set_all_requested_presences
+tp_account_manager_enable_restart
+<SUBSECTION>
+TP_ACCOUNT_MANAGER_FEATURE_CORE
+tp_account_manager_is_prepared
+tp_account_manager_prepare_async
+tp_account_manager_prepare_finish
+<SUBSECTION Private>
+tp_account_manager_get_feature_quark_core
<SUBSECTION>
tp_cli_account_manager_callback_for_create_account
tp_cli_account_manager_call_create_account
diff --git a/examples/extensions/Makefile.am b/examples/extensions/Makefile.am
index 2053010f9..ad15f475b 100644
--- a/examples/extensions/Makefile.am
+++ b/examples/extensions/Makefile.am
@@ -9,8 +9,6 @@
tools_dir = $(top_srcdir)/tools
-include $(tools_dir)/shave.mk
-
AM_CFLAGS = \
$(ERROR_CFLAGS) \
$(DBUS_CFLAGS) \
@@ -68,43 +66,43 @@ XSLTPROCFLAGS = --nonet --novalid
_gen/all.xml: all.xml $(wildcard *.xml) $(tools_dir)/xincludator.py
$(mkdir_p) _gen
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/xincludator.py $< > $@
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/xincludator.py $< > $@
extensions.html: _gen/all.xml $(tools_dir)/doc-generator.xsl
- $(QUIET_GEN)$(XSLTPROC) $(XSLTPROCFLAGS) \
+ $(AM_V_GEN)$(XSLTPROC) $(XSLTPROCFLAGS) \
$(tools_dir)/doc-generator.xsl \
$< > $@
_gen/gtypes.h _gen/gtypes-body.h: _gen/all.xml \
$(top_srcdir)/tools/glib-gtypes-generator.py
- $(QUIET_GEN)$(PYTHON) $(top_srcdir)/tools/glib-gtypes-generator.py \
+ $(AM_V_GEN)$(PYTHON) $(top_srcdir)/tools/glib-gtypes-generator.py \
$< _gen/gtypes Example
_gen/signals-marshal.list: _gen/all.xml \
$(tools_dir)/glib-signals-marshal-gen.py
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/glib-signals-marshal-gen.py $< > $@
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-signals-marshal-gen.py $< > $@
_gen/signals-marshal.h: _gen/signals-marshal.list Makefile.am
- $(QUIET_GEN)$(GLIB_GENMARSHAL) --header --prefix=_example_ext_marshal $< > $@
+ $(AM_V_GEN)$(GLIB_GENMARSHAL) --header --prefix=_example_ext_marshal $< > $@
_gen/signals-marshal.c: _gen/signals-marshal.list Makefile.am
- $(QUIET_GEN){ echo '#include "_gen/signals-marshal.h"' && \
+ $(AM_V_GEN){ echo '#include "_gen/signals-marshal.h"' && \
$(GLIB_GENMARSHAL) --body --prefix=_example_ext_marshal $< ; } > $@
_gen/register-dbus-glib-marshallers-body.h: _gen/all.xml \
$(tools_dir)/glib-client-marshaller-gen.py
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/glib-client-marshaller-gen.py $< \
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-client-marshaller-gen.py $< \
_example_ext > $@
_gen/enums.h: _gen/all.xml \
$(tools_dir)/c-constants-gen.py
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/c-constants-gen.py \
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/c-constants-gen.py \
Example \
$< > $@
_gen/interfaces-body.h _gen/interfaces.h: _gen/all.xml \
$(tools_dir)/glib-interfaces-gen.py
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/glib-interfaces-gen.py \
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-interfaces-gen.py \
Example _gen/interfaces-body.h _gen/interfaces.h $<
# Generated files which must be generated per "category". Each TpProxy
@@ -113,11 +111,11 @@ _gen/interfaces-body.h _gen/interfaces.h: _gen/all.xml \
_gen/connection.xml: connection.xml $(wildcard *.xml) $(tools_dir)/xincludator.py
$(mkdir_p) _gen
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/xincludator.py $< > $@
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/xincludator.py $< > $@
_gen/cli-connection-body.h _gen/cli-connection.h: _gen/connection.xml \
$(tools_dir)/glib-client-gen.py Makefile.am
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/glib-client-gen.py \
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-client-gen.py \
--group=connection \
--subclass=TpConnection \
--subclass-assert=TP_IS_CONNECTION \
@@ -128,7 +126,7 @@ _gen/cli-connection-body.h _gen/cli-connection.h: _gen/connection.xml \
_gen/svc-connection.c _gen/svc-connection.h: _gen/connection.xml \
$(tools_dir)/glib-ginterface-gen.py
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/glib-ginterface-gen.py \
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-ginterface-gen.py \
--filename=_gen/svc-connection \
--signal-marshal-prefix=_example_ext \
--include='<telepathy-glib/dbus.h>' \
diff --git a/m4/Makefile.am b/m4/Makefile.am
index e72117c91..e04d0cb39 100644
--- a/m4/Makefile.am
+++ b/m4/Makefile.am
@@ -3,5 +3,4 @@ compiler.m4 \
gtk-doc.m4 \
linker.m4 \
tp-compiler-flag.m4 \
-tp-compiler-warnings.m4 \
-shave.m4
+tp-compiler-warnings.m4
diff --git a/m4/shave.m4 b/m4/shave.m4
deleted file mode 100644
index 0a3509e59..000000000
--- a/m4/shave.m4
+++ /dev/null
@@ -1,77 +0,0 @@
-dnl Make automake/libtool output more friendly to humans
-dnl Damien Lespiau <damien.lespiau@gmail.com>
-dnl
-dnl SHAVE_INIT([shavedir],[default_mode])
-dnl
-dnl shavedir: the directory where the shave scripts are, it defaults to
-dnl $(top_builddir)
-dnl default_mode: (enable|disable) default shave mode. This parameter
-dnl controls shave's behaviour when no option has been
-dnl given to configure. It defaults to disable.
-dnl
-dnl * SHAVE_INIT should be called late in your configure.(ac|in) file (just
-dnl before AC_CONFIG_FILE/AC_OUTPUT is perfect. This macro rewrites CC and
-dnl LIBTOOL, you don't want the configure tests to have these variables
-dnl re-defined.
-dnl * This macro requires GNU make's -s option.
-
-AC_DEFUN([_SHAVE_ARG_ENABLE],
-[
- AC_ARG_ENABLE([shave],
- AS_HELP_STRING(
- [--enable-shave],
- [use shave to make the build pretty [[default=$1]]]),,
- [enable_shave=$1]
- )
-])
-
-AC_DEFUN([SHAVE_INIT],
-[
- dnl you can tweak the default value of enable_shave
- m4_if([$2], [enable], [_SHAVE_ARG_ENABLE(yes)], [_SHAVE_ARG_ENABLE(no)])
-
- if test x"$enable_shave" = xyes; then
- dnl where can we find the shave scripts?
- m4_if([$1],,
- [shavedir="$ac_pwd"],
- [shavedir="$ac_pwd/$1"])
- AC_SUBST(shavedir)
-
- dnl make is now quiet
- AC_SUBST([MAKEFLAGS], [-s])
- AC_SUBST([AM_MAKEFLAGS], ['`test -z $V && echo -s`'])
-
- dnl we need sed
- AC_CHECK_PROG(SED,sed,sed,false)
-
- dnl substitute libtool
- SHAVE_SAVED_LIBTOOL=$LIBTOOL
- LIBTOOL="${SHELL} ${shavedir}/shave-libtool '${SHAVE_SAVED_LIBTOOL}'"
- AC_SUBST(LIBTOOL)
-
- dnl substitute cc/cxx
- SHAVE_SAVED_CC=$CC
- SHAVE_SAVED_CXX=$CXX
- SHAVE_SAVED_FC=$FC
- SHAVE_SAVED_F77=$F77
- SHAVE_SAVED_OBJC=$OBJC
- CC="${SHELL} ${shavedir}/shave cc ${SHAVE_SAVED_CC}"
- CXX="${SHELL} ${shavedir}/shave cxx ${SHAVE_SAVED_CXX}"
- FC="${SHELL} ${shavedir}/shave fc ${SHAVE_SAVED_FC}"
- F77="${SHELL} ${shavedir}/shave f77 ${SHAVE_SAVED_F77}"
- OBJC="${SHELL} ${shavedir}/shave objc ${SHAVE_SAVED_OBJC}"
- AC_SUBST(CC)
- AC_SUBST(CXX)
- AC_SUBST(FC)
- AC_SUBST(F77)
- AC_SUBST(OBJC)
-
- V=@
- else
- V=1
- fi
- Q='$(V:1=)'
- AC_SUBST(V)
- AC_SUBST(Q)
-])
-
diff --git a/shave-libtool.in b/shave-libtool.in
deleted file mode 100644
index 1f3a720c1..000000000
--- a/shave-libtool.in
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/bin/sh
-
-# we need sed
-SED=@SED@
-if test -z "$SED" ; then
-SED=sed
-fi
-
-lt_unmangle ()
-{
- last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'`
-}
-
-# the real libtool to use
-LIBTOOL="$1"
-shift
-
-# if 1, don't print anything, the underlaying wrapper will do it
-pass_though=0
-
-# scan the arguments, keep the right ones for libtool, and discover the mode
-preserved_args=
-while test "$#" -gt 0; do
- opt="$1"
- shift
-
- case $opt in
- --mode=*)
- mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'`
- preserved_args="$preserved_args $opt"
- ;;
- -o)
- lt_output="$1"
- preserved_args="$preserved_args $opt"
- ;;
- *)
- preserved_args="$preserved_args $opt"
- ;;
- esac
-done
-
-case "$mode" in
-compile)
- # shave will be called and print the actual CC/CXX/LINK line
- preserved_args="$preserved_args --shave-mode=$mode"
- pass_though=1
- ;;
-link)
- preserved_args="$preserved_args --shave-mode=$mode"
- Q=" LINK "
- ;;
-*)
- # let's u
- # echo "*** libtool: Unimplemented mode: $mode, fill a bug report"
- ;;
-esac
-
-lt_unmangle "$lt_output"
-output=$last_result
-
-if test -z $V; then
- if test $pass_though -eq 0; then
- echo "$Q$output"
- fi
- $LIBTOOL --silent $preserved_args
-else
- echo $LIBTOOL $preserved_args
- $LIBTOOL $preserved_args
-fi
diff --git a/shave.in b/shave.in
deleted file mode 100644
index 5c16f27ae..000000000
--- a/shave.in
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/bin/sh
-
-# we need sed
-SED=@SED@
-if test -z "$SED" ; then
-SED=sed
-fi
-
-lt_unmangle ()
-{
- last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'`
-}
-
-# the tool to wrap (cc, cxx, ar, ranlib, ..)
-tool="$1"
-shift
-
-# the reel tool (to call)
-REEL_TOOL="$1"
-shift
-
-pass_through=0
-preserved_args=
-while test "$#" -gt 0; do
- opt="$1"
- shift
-
- case $opt in
- --shave-mode=*)
- mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'`
- ;;
- -o)
- lt_output="$1"
- preserved_args="$preserved_args $opt"
- ;;
- *)
- preserved_args="$preserved_args $opt"
- ;;
- esac
-done
-
-# mode=link is handled in the libtool wrapper
-case "$mode,$tool" in
-link,*)
- pass_through=1
- ;;
-*,cxx)
- Q=" CXX "
- ;;
-*,cc)
- Q=" CC "
- ;;
-*,fc)
- Q=" FC "
- ;;
-*,f77)
- Q=" F77 "
- ;;
-*,objc)
- Q=" OBJC "
- ;;
-*,*)
- # should not happen
- Q=" CC "
- ;;
-esac
-
-lt_unmangle "$lt_output"
-output=$last_result
-
-if test -z $V; then
- if test $pass_through -eq 0; then
- echo "$Q$output"
- fi
- $REEL_TOOL $preserved_args
-else
- echo $REEL_TOOL $preserved_args
- $REEL_TOOL $preserved_args
-fi
diff --git a/telepathy-glib/Makefile.am b/telepathy-glib/Makefile.am
index 7a65ee509..a29b71555 100644
--- a/telepathy-glib/Makefile.am
+++ b/telepathy-glib/Makefile.am
@@ -1,4 +1,3 @@
-include $(top_srcdir)/tools/shave.mk
include $(top_srcdir)/tools/flymake.mk
tpgincludedir=$(includedir)/telepathy-1.0/telepathy-glib
@@ -40,7 +39,8 @@ ABI_LISTS = \
versions/0.7.34.abi \
versions/0.7.35.abi \
versions/0.7.36.abi \
- versions/0.7.37.abi
+ versions/0.7.37.abi \
+ versions/0.9.0.abi
EXTRA_DIST = \
$(ABI_LISTS) \
@@ -96,7 +96,7 @@ endif
_gen/version-script.txt: $(ABI_LISTS) _gen/abi.txt Makefile.am \
$(top_srcdir)/tools/make-version-script.py
- $(QUIET_GEN)$(PYTHON) $(top_srcdir)/tools/make-version-script.py \
+ $(AM_V_GEN)$(PYTHON) $(top_srcdir)/tools/make-version-script.py \
--symbols=_gen/abi.txt $(MAKE_VERSION_SCRIPT_FLAGS) \
$(ABI_LISTS:%=$(srcdir)/%) > $@
$(PYTHON) $(top_srcdir)/tools/make-version-script.py \
@@ -114,7 +114,7 @@ _gen/abi.txt: libtelepathy-glib-internal.la Makefile.am
grep " [DT] " < _gen/abi.nm > _gen/abi.funcs
cut -d" " -f3 < _gen/abi.funcs > _gen/abi.funcnames
grep "^tp" < _gen/abi.funcnames > _gen/abi.tpfuncnames
- $(QUIET_GEN)sort -u < _gen/abi.tpfuncnames > $@
+ $(AM_V_GEN)sort -u < _gen/abi.tpfuncnames > $@
libtelepathy_glib_la_LDFLAGS += \
$(VERSION_SCRIPT_ARG)=_gen/version-script.txt
@@ -280,7 +280,9 @@ check-local: check-coding-style
libtelepathy_glib_internal_la_LIBADD = $(ALL_LIBS)
libtelepathy_glib_internal_la_SOURCES = \
account.c \
+ account-internal.h \
account-manager.c \
+ account-manager-internal.h \
base-connection.c \
base-connection-manager.c \
channel.c \
@@ -360,60 +362,60 @@ _gen/stable-stamp: $(wildcard *.xml) _gen/spec-stamp
touch $@
_gen/stable-spec.xml: stable-interfaces.xml _gen/stable-stamp $(tools_dir)/xincludator.py
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/xincludator.py $< > $@
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/xincludator.py $< > $@
# Things generated from the whole spec at once
_gen/gtypes.h _gen/gtypes-body.h: _gen/stable-spec.xml \
$(tools_dir)/glib-gtypes-generator.py
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/glib-gtypes-generator.py \
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-gtypes-generator.py \
_gen/stable-spec.xml \
_gen/gtypes Tp
_gen/telepathy-enums.h: _gen/stable-spec.xml \
$(tools_dir)/c-constants-gen.py
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/c-constants-gen.py \
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/c-constants-gen.py \
Tp \
$< > $@
_gen/interfaces-body.h _gen/telepathy-interfaces.h: _gen/stable-spec.xml \
$(tools_dir)/glib-interfaces-gen.py
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/glib-interfaces-gen.py \
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-interfaces-gen.py \
Tp _gen/interfaces-body.h _gen/telepathy-interfaces.h $<
_gen/register-dbus-glib-marshallers-body.h: _gen/stable-spec.xml \
$(tools_dir)/glib-client-marshaller-gen.py
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/glib-client-marshaller-gen.py $< _tp > $@
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-client-marshaller-gen.py $< _tp > $@
_gen/tp-signals-marshal.list: $(tools_dir)/glib-signals-marshal-gen.py \
_gen/stable-spec.xml
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/glib-signals-marshal-gen.py \
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-signals-marshal-gen.py \
_gen/stable-spec.xml > $@
_gen/signals-marshal.list: signals-marshal.list _gen/tp-signals-marshal.list
- $(QUIET_GEN)sort -u $^ > $@
+ $(AM_V_GEN)sort -u $^ > $@
_gen/signals-marshal.h: _gen/signals-marshal.list Makefile.am
- $(QUIET_GEN)$(GLIB_GENMARSHAL) --header --prefix=_tp_marshal $< > $@
+ $(AM_V_GEN)$(GLIB_GENMARSHAL) --header --prefix=_tp_marshal $< > $@
_gen/signals-marshal.c: _gen/signals-marshal.list Makefile.am
- $(QUIET_GEN){ echo '#include "_gen/signals-marshal.h"' && \
+ $(AM_V_GEN){ echo '#include "_gen/signals-marshal.h"' && \
$(GLIB_GENMARSHAL) --body --prefix=_tp_marshal $< ; } > $@
_gen/error-str.h _gen/error-str.c: _gen/stable-spec.xml \
$(tools_dir)/glib-errors-str-gen.py
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/glib-errors-str-gen.py \
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-errors-str-gen.py \
_gen/error-str $<
# Things generated per interface
_gen/tp-spec-%.xml: %.xml _gen/spec-stamp $(tools_dir)/xincludator.py
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/xincludator.py $< > $@
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/xincludator.py $< > $@
_gen/tp-svc-%.c _gen/tp-svc-%.h: _gen/tp-spec-%.xml \
$(tools_dir)/glib-ginterface-gen.py \
Makefile.am
- $(QUIET_GEN)$(PYTHON) $(tools_dir)/glib-ginterface-gen.py \
+ $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-ginterface-gen.py \
--filename=_gen/tp-svc-$* \
--signal-marshal-prefix=_tp \
--include='<telepathy-glib/dbus.h>' \
@@ -424,7 +426,7 @@ _gen/tp-svc-%.c _gen/tp-svc-%.h: _gen/tp-spec-%.xml \
_gen/tp-cli-%-body.h _gen/tp-cli-%.h: _gen/tp-spec-%.xml \
$(tools_dir)/glib-client-gen.py \
Makefile.am
- $(QUIET_GEN)set -e; \
+ $(AM_V_GEN)set -e; \
subclass= ; \
subclass_assert= ; \
case $* in \
diff --git a/telepathy-glib/account-internal.h b/telepathy-glib/account-internal.h
new file mode 100644
index 000000000..2fbf071f5
--- /dev/null
+++ b/telepathy-glib/account-internal.h
@@ -0,0 +1,39 @@
+/*
+ * TpAccount - proxy for a Telepathy account (internals)
+ *
+ * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TP_ACCOUNT_INTERNAL_H
+#define TP_ACCOUNT_INTERNAL_H
+
+#include <telepathy-glib/account.h>
+
+G_BEGIN_DECLS
+
+const GQuark * _tp_account_get_requested_features (TpAccount *account);
+
+const GQuark * _tp_account_get_actual_features (TpAccount *account);
+
+const GQuark * _tp_account_get_missing_features (TpAccount *account);
+
+void _tp_account_refresh_properties (TpAccount *account);
+
+G_END_DECLS
+
+#endif
diff --git a/telepathy-glib/account-manager-internal.h b/telepathy-glib/account-manager-internal.h
new file mode 100644
index 000000000..18dbeef75
--- /dev/null
+++ b/telepathy-glib/account-manager-internal.h
@@ -0,0 +1,40 @@
+/*
+ * TpAccountManager - proxy for a Telepathy account manager (internals)
+ *
+ * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TP_ACCOUNT_MANAGER_INTERNAL_H
+#define TP_ACCOUNT_MANAGER_INTERNAL_H
+
+#include <telepathy-glib/account-manager.h>
+
+G_BEGIN_DECLS
+
+const GQuark * _tp_account_manager_get_requested_features (
+ TpAccountManager *manager);
+
+const GQuark * _tp_account_manager_get_actual_features (
+ TpAccountManager *manager);
+
+const GQuark * _tp_account_manager_get_missing_features (
+ TpAccountManager *manager);
+
+G_END_DECLS
+
+#endif
diff --git a/telepathy-glib/account-manager.c b/telepathy-glib/account-manager.c
index e147358ce..59b6fa94c 100644
--- a/telepathy-glib/account-manager.c
+++ b/telepathy-glib/account-manager.c
@@ -19,13 +19,17 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "telepathy-glib/account-manager.h"
+#include "telepathy-glib/account-manager-internal.h"
+#include "telepathy-glib/account-internal.h"
-#include <telepathy-glib/dbus.h>
#include <telepathy-glib/defs.h>
-#include <telepathy-glib/errors.h>
+#include <telepathy-glib/gtypes.h>
#include <telepathy-glib/interfaces.h>
#include <telepathy-glib/proxy-subclass.h>
+#include <telepathy-glib/util.h>
+
+#include "telepathy-glib/account-manager.h"
+#include "telepathy-glib/_gen/signals-marshal.h"
#define DEBUG_FLAG TP_DEBUG_ACCOUNTS
#include "telepathy-glib/debug-internal.h"
@@ -51,14 +55,6 @@
* their configuration, places accounts online on request, and manipulates
* accounts' presence, nicknames and avatars.
*
- * This proxy is usable but incomplete: GObject signals and accessors for the
- * D-Bus properties will be added in a later version of telepathy-glib, along
- * with a mechanism similar to tp_connection_call_when_ready().
- *
- * Until suitable convenience methods are implemented, the generic
- * tp_cli_dbus_properties_call_get_all() method can be used to get the D-Bus
- * properties.
- *
* Since: 0.7.32
*/
@@ -69,29 +65,594 @@
*/
struct _TpAccountManagerPrivate {
- gpointer dummy;
+ /* (owned) object path -> (reffed) TpAccount */
+ GHashTable *accounts;
+ gboolean dispose_run;
+
+ /* most available presence */
+ TpAccount *most_available_account;
+
+ TpConnectionPresenceType most_available_presence;
+ gchar *most_available_status;
+ gchar *most_available_status_message;
+
+ /* requested presence, could be different
+ * from the actual one. */
+ TpConnectionPresenceType requested_presence;
+ gchar *requested_status;
+ gchar *requested_status_message;
+
+ GHashTable *create_results;
+
+ /* Features */
+ GList *features;
+ GList *callbacks;
+ GArray *requested_features;
+ GArray *actual_features;
+ GArray *missing_features;
+};
+
+typedef struct {
+ GQuark name;
+ gboolean ready;
+} TpAccountManagerFeature;
+
+typedef struct {
+ GSimpleAsyncResult *result;
+ const GQuark *features;
+} TpAccountManagerFeatureCallback;
+
+#define MC5_BUS_NAME "org.freedesktop.Telepathy.MissionControl5"
+
+enum {
+ ACCOUNT_VALIDITY_CHANGED,
+ ACCOUNT_REMOVED,
+ ACCOUNT_ENABLED,
+ ACCOUNT_DISABLED,
+ MOST_AVAILABLE_PRESENCE_CHANGED,
+ LAST_SIGNAL
};
+static guint signals[LAST_SIGNAL];
+
G_DEFINE_TYPE (TpAccountManager, tp_account_manager, TP_TYPE_PROXY);
+/**
+ * TP_ACCOUNT_MANAGER_FEATURE_CORE:
+ *
+ * Expands to a call to a function that returns a quark for the "core" feature
+ * on a #TpAccountManager.
+ *
+ * When this feature is prepared, the list of accounts have been retrieved and
+ * are available for use, and change-notification has been set up.
+ *
+ * One can ask for a feature to be prepared using the
+ * tp_account_manager_prepare_async() function, and waiting for it to callback.
+ *
+ * Since: 0.9.0
+ */
+
+/**
+ * tp_account_manager_get_feature_quark_core:
+ *
+ * <!-- -->
+ *
+ * Returns: the quark used for representing the core feature of a
+ * #TpAccountManager
+ *
+ * Since: 0.9.0
+ */
+GQuark
+tp_account_manager_get_feature_quark_core (void)
+{
+ return g_quark_from_static_string ("tp-account-manager-feature-core");
+}
+
+static const GQuark *
+_tp_account_manager_get_known_features (void)
+{
+ static GQuark features[1] = { 0 };
+
+ if (G_UNLIKELY (features[0] == 0))
+ {
+ features[0] = TP_ACCOUNT_MANAGER_FEATURE_CORE;
+ }
+
+ return features;
+}
+
+static TpAccountManagerFeature *
+_tp_account_manager_get_feature (TpAccountManager *self,
+ GQuark feature)
+{
+ TpAccountManagerPrivate *priv = self->priv;
+ GList *l;
+
+ for (l = priv->features; l != NULL; l = l->next)
+ {
+ TpAccountManagerFeature *f = l->data;
+
+ if (f->name == feature)
+ return f;
+ }
+
+ return NULL;
+}
+
+static gboolean
+_tp_account_manager_feature_in_array (GQuark feature,
+ const GArray *array)
+{
+ const GQuark *c = (const GQuark *) array->data;
+
+ for (; *c != 0; c++)
+ {
+ if (*c == feature)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+_tp_account_manager_check_features (TpAccountManager *self,
+ const GQuark *features)
+{
+ const GQuark *f;
+ TpAccountManagerFeature *feat;
+
+ for (f = features; f != NULL && *f != 0; f++)
+ {
+ feat = _tp_account_manager_get_feature (self, *f);
+
+ /* features which are NULL (ie. don't exist) are always considered as
+ * being ready, except in _is_prepared when it doesn't make sense to
+ * return TRUE. */
+ if (feat != NULL && !feat->ready)
+ return FALSE;
+ }
+
+ /* Special-case core: no other feature is ready unless core itself is
+ * ready. */
+ feat = _tp_account_manager_get_feature (self,
+ TP_ACCOUNT_MANAGER_FEATURE_CORE);
+ if (!feat->ready)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+_tp_account_manager_become_ready (TpAccountManager *self,
+ GQuark feature)
+{
+ TpAccountManagerPrivate *priv = self->priv;
+ TpAccountManagerFeature *f = NULL;
+ GList *l, *remove = NULL;
+
+ f = _tp_account_manager_get_feature (self, feature);
+
+ g_assert (f != NULL);
+
+ if (f->ready)
+ return;
+
+ f->ready = TRUE;
+
+ if (!_tp_account_manager_feature_in_array (feature, priv->actual_features))
+ g_array_append_val (priv->actual_features, feature);
+
+ /* First, find which callbacks are satisfied and add those items
+ * from the remove list. */
+ l = priv->callbacks;
+ while (l != NULL)
+ {
+ GList *c = l;
+ TpAccountManagerFeatureCallback *cb = l->data;
+
+ l = l->next;
+
+ if (_tp_account_manager_check_features (self, cb->features))
+ {
+ priv->callbacks = g_list_remove_link (priv->callbacks, c);
+ remove = g_list_concat (c, remove);
+ }
+ }
+
+ /* Next, complete these callbacks */
+ for (l = remove; l != NULL; l = l->next)
+ {
+ TpAccountManagerFeatureCallback *cb = l->data;
+
+ g_simple_async_result_complete (cb->result);
+ g_object_unref (cb->result);
+ g_slice_free (TpAccountManagerFeatureCallback, cb);
+ }
+
+ g_list_free (remove);
+}
+
static void
tp_account_manager_init (TpAccountManager *self)
{
- self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TYPE_ACCOUNT_MANAGER,
+ TpAccountManagerPrivate *priv;
+
+ priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TYPE_ACCOUNT_MANAGER,
TpAccountManagerPrivate);
+
+ self->priv = priv;
+
+ priv->most_available_presence = TP_CONNECTION_PRESENCE_TYPE_UNSET;
+
+ priv->accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify) g_object_unref);
+
+ priv->create_results = g_hash_table_new (g_direct_hash, g_direct_equal);
+}
+
+static void
+_tp_account_manager_start_mc5 (TpDBusDaemon *bus)
+{
+ TpProxy *mc5_proxy;
+
+ /* trigger MC5 starting */
+ mc5_proxy = g_object_new (TP_TYPE_PROXY,
+ "dbus-daemon", bus,
+ "dbus-connection", tp_proxy_get_dbus_connection (TP_PROXY (bus)),
+ "bus-name", MC5_BUS_NAME,
+ "object-path", "/",
+ NULL);
+
+ tp_cli_dbus_peer_call_ping (mc5_proxy, -1, NULL, NULL, NULL, NULL);
+
+ g_object_unref (mc5_proxy);
+}
+
+static void
+_tp_account_manager_name_owner_cb (TpDBusDaemon *proxy,
+ const gchar *name,
+ const gchar *new_owner,
+ gpointer user_data)
+{
+ DEBUG ("Name owner changed for %s, new name: %s", name, new_owner);
+
+ if (new_owner == NULL || new_owner[0] == '\0')
+ {
+ /* MC5 quit or crashed for some reason, let's start it again */
+ _tp_account_manager_start_mc5 (proxy);
+ return;
+ }
+}
+
+static void
+_tp_account_manager_validity_changed_cb (TpAccountManager *proxy,
+ const gchar *path,
+ gboolean valid,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ TpAccountManager *manager = TP_ACCOUNT_MANAGER (weak_object);
+ TpAccountManagerPrivate *priv = manager->priv;
+ TpAccount *account;
+
+ account = tp_account_manager_ensure_account (manager, path);
+
+ g_object_ref (account);
+
+ if (!valid)
+ g_hash_table_remove (priv->accounts, path);
+
+ g_signal_emit (manager, signals[ACCOUNT_VALIDITY_CHANGED], 0,
+ account, valid);
+
+ g_object_unref (account);
+}
+
+static void
+_tp_account_manager_ensure_all_accounts (TpAccountManager *manager,
+ GPtrArray *valid_accounts,
+ GPtrArray *invalid_accounts)
+{
+ guint i, missing_accounts;
+ GHashTableIter iter;
+ TpAccountManagerPrivate *priv = manager->priv;
+ gpointer value;
+ TpAccount *account;
+ gboolean found_in_valid = FALSE;
+ gboolean found_in_invalid = FALSE;
+ const gchar *name;
+
+ /* ensure all accounts coming from MC5 first */
+ for (i = 0; i < valid_accounts->len; i++)
+ {
+ name = g_ptr_array_index (valid_accounts, i);
+
+ account = tp_account_manager_ensure_account (manager, name);
+ _tp_account_refresh_properties (account);
+ }
+
+ missing_accounts = g_hash_table_size (priv->accounts) - valid_accounts->len;
+
+ if (missing_accounts > 0)
+ {
+ /* look for accounts we have and the TpAccountManager doesn't,
+ * and remove them from our cache. */
+
+ DEBUG ("%d missing accounts", missing_accounts);
+
+ g_hash_table_iter_init (&iter, priv->accounts);
+
+ while (g_hash_table_iter_next (&iter, NULL, &value) && missing_accounts > 0)
+ {
+ account = value;
+
+ /* look for this account in the valid accounts array */
+ for (i = 0; i < valid_accounts->len; i++)
+ {
+ name = g_ptr_array_index (valid_accounts, i);
+
+ if (!tp_strdiff (name, tp_proxy_get_object_path (account)))
+ {
+ found_in_valid = TRUE;
+ break;
+ }
+ }
+
+ if (!found_in_valid)
+ {
+ /* look for this account in the invalid accounts array */
+ for (i = 0; i < invalid_accounts->len; i++)
+ {
+ name = g_ptr_array_index (invalid_accounts, i);
+
+ if (!tp_strdiff (name, tp_proxy_get_object_path (account)))
+ {
+ found_in_invalid = TRUE;
+ break;
+ }
+ }
+
+ if (found_in_invalid)
+ {
+ DEBUG ("Account %s's validity changed",
+ tp_proxy_get_object_path (account));
+
+ _tp_account_manager_validity_changed_cb (manager,
+ tp_proxy_get_object_path (account), FALSE, NULL,
+ G_OBJECT (manager));
+ }
+ else
+ {
+ DEBUG ("Account %s was not found, remove it from the cache",
+ tp_proxy_get_object_path (account));
+
+ g_object_ref (account);
+ g_hash_table_iter_remove (&iter);
+ g_signal_emit (manager, signals[ACCOUNT_REMOVED], 0, account);
+ g_object_unref (account);
+ }
+
+ missing_accounts--;
+ }
+
+ found_in_valid = FALSE;
+ found_in_invalid = FALSE;
+ }
+ }
+}
+
+static void
+_tp_account_manager_update_most_available_presence (TpAccountManager *manager)
+{
+ TpAccountManagerPrivate *priv = manager->priv;
+ TpConnectionPresenceType presence = TP_CONNECTION_PRESENCE_TYPE_OFFLINE;
+ TpAccount *account = NULL;
+ GHashTableIter iter;
+ gpointer value;
+
+ /* this presence is equal to the presence of the account with the
+ * highest availability */
+
+ g_hash_table_iter_init (&iter, priv->accounts);
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ TpAccount *a = TP_ACCOUNT (value);
+ TpConnectionPresenceType p;
+
+ p = tp_account_get_current_presence (a, NULL, NULL);
+
+ if (tp_connection_presence_type_cmp_availability (p, presence) > 0)
+ {
+ account = a;
+ presence = p;
+ }
+ }
+
+ priv->most_available_account = account;
+ g_free (priv->most_available_status);
+ g_free (priv->most_available_status_message);
+
+ if (account == NULL)
+ {
+ priv->most_available_presence = presence;
+ priv->most_available_status = NULL;
+ priv->most_available_status_message = NULL;
+ return;
+ }
+
+ priv->most_available_presence = tp_account_get_current_presence (account,
+ &(priv->most_available_status), &(priv->most_available_status_message));
+
+ DEBUG ("Updated most available presence to: %s (%d) \"%s\"",
+ priv->most_available_status, priv->most_available_presence,
+ priv->most_available_status_message);
}
static void
-tp_account_manager_constructed (GObject *object)
+_tp_account_manager_check_core_ready (TpAccountManager *manager)
+{
+ TpAccountManagerPrivate *priv = manager->priv;
+ GHashTableIter iter;
+ gpointer value;
+
+ if (tp_account_manager_is_prepared (manager, TP_ACCOUNT_MANAGER_FEATURE_CORE))
+ return;
+
+ g_hash_table_iter_init (&iter, priv->accounts);
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ TpAccount *account = TP_ACCOUNT (value);
+
+ if (!tp_account_is_prepared (account, TP_ACCOUNT_FEATURE_CORE))
+ return;
+ }
+
+ /* Rerequest most available presence on the initial set of accounts for cases
+ * where a most available presence was requested before the manager was ready
+ */
+ if (priv->requested_presence != TP_CONNECTION_PRESENCE_TYPE_UNSET)
+ {
+ tp_account_manager_set_all_requested_presences (manager,
+ priv->requested_presence, priv->requested_status,
+ priv->requested_status_message);
+ }
+
+ _tp_account_manager_update_most_available_presence (manager);
+
+ _tp_account_manager_become_ready (manager, TP_ACCOUNT_MANAGER_FEATURE_CORE);
+}
+
+static void
+_tp_account_manager_got_all_cb (TpProxy *proxy,
+ GHashTable *properties,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ TpAccountManager *manager = TP_ACCOUNT_MANAGER (weak_object);
+ GPtrArray *valid_accounts;
+ GPtrArray *invalid_accounts;
+
+ if (error != NULL)
+ {
+ DEBUG ("Failed to get account manager properties: %s", error->message);
+ return;
+ }
+
+ valid_accounts = tp_asv_get_boxed (properties, "ValidAccounts",
+ TP_ARRAY_TYPE_OBJECT_PATH_LIST);
+
+ invalid_accounts = tp_asv_get_boxed (properties, "InvalidAccounts",
+ TP_ARRAY_TYPE_OBJECT_PATH_LIST);
+
+ if (valid_accounts != NULL && invalid_accounts != NULL)
+ _tp_account_manager_ensure_all_accounts (manager, valid_accounts,
+ invalid_accounts);
+
+ _tp_account_manager_check_core_ready (manager);
+}
+
+static void
+_tp_account_manager_constructed (GObject *object)
{
TpAccountManager *self = TP_ACCOUNT_MANAGER (object);
void (*chain_up) (GObject *) =
((GObjectClass *) tp_account_manager_parent_class)->constructed;
+ TpAccountManagerPrivate *priv = self->priv;
+ guint i;
+ const GQuark *known_features;
if (chain_up != NULL)
chain_up (object);
g_return_if_fail (tp_proxy_get_dbus_daemon (self) != NULL);
+
+ priv->features = NULL;
+ priv->callbacks = NULL;
+
+ priv->requested_features = g_array_new (TRUE, FALSE, sizeof (GQuark));
+ priv->actual_features = g_array_new (TRUE, FALSE, sizeof (GQuark));
+ priv->missing_features = g_array_new (TRUE, FALSE, sizeof (GQuark));
+
+ known_features = _tp_account_manager_get_known_features ();
+
+ /* Fill features list. */
+ for (i = 0; i < G_N_ELEMENTS (known_features); i++)
+ {
+ TpAccountManagerFeature *feature;
+ feature = g_slice_new0 (TpAccountManagerFeature);
+ feature->name = known_features[i];
+ feature->ready = FALSE;
+ priv->features = g_list_prepend (priv->features, feature);
+ }
+
+ tp_cli_account_manager_connect_to_account_validity_changed (self,
+ _tp_account_manager_validity_changed_cb, NULL,
+ NULL, G_OBJECT (self), NULL);
+
+ tp_cli_dbus_properties_call_get_all (self, -1, TP_IFACE_ACCOUNT_MANAGER,
+ _tp_account_manager_got_all_cb, NULL, NULL, G_OBJECT (self));
+}
+
+static void
+_tp_account_manager_feature_free (gpointer data,
+ gpointer user_data)
+{
+ g_slice_free (TpAccountManagerFeature, data);
+}
+
+static void
+_tp_account_manager_finalize (GObject *object)
+{
+ TpAccountManager *manager = TP_ACCOUNT_MANAGER (object);
+ TpAccountManagerPrivate *priv = manager->priv;
+
+ g_free (priv->most_available_status);
+ g_free (priv->most_available_status_message);
+
+ g_free (priv->requested_status);
+ g_free (priv->requested_status_message);
+
+ g_list_foreach (priv->features, _tp_account_manager_feature_free, NULL);
+ g_list_free (priv->features);
+ priv->features = NULL;
+
+ /* GSimpleAsyncResult keeps a ref to the source GObject, so this list
+ * should be empty. */
+ g_assert_cmpuint (g_list_length (priv->callbacks), ==, 0);
+ g_list_free (priv->callbacks);
+ priv->callbacks = NULL;
+
+ g_array_free (priv->requested_features, TRUE);
+ g_array_free (priv->actual_features, TRUE);
+ g_array_free (priv->missing_features, TRUE);
+
+ G_OBJECT_CLASS (tp_account_manager_parent_class)->finalize (object);
+}
+
+static void
+_tp_account_manager_dispose (GObject *object)
+{
+ TpAccountManager *self = TP_ACCOUNT_MANAGER (object);
+ TpAccountManagerPrivate *priv = self->priv;
+
+ if (priv->dispose_run)
+ return;
+
+ priv->dispose_run = TRUE;
+
+ /* GSimpleAsyncResult keeps a ref to the source GObject, so this hash
+ * table should be empty. */
+ g_assert_cmpuint (g_hash_table_size (priv->create_results), ==, 0);
+ g_hash_table_destroy (priv->create_results);
+ priv->create_results = NULL;
+
+ g_hash_table_destroy (priv->accounts);
+
+ tp_dbus_daemon_cancel_name_owner_watch (tp_proxy_get_dbus_daemon (self),
+ TP_ACCOUNT_MANAGER_BUS_NAME, _tp_account_manager_name_owner_cb, self);
+
+ G_OBJECT_CLASS (tp_account_manager_parent_class)->dispose (object);
}
static void
@@ -102,10 +663,113 @@ tp_account_manager_class_init (TpAccountManagerClass *klass)
g_type_class_add_private (klass, sizeof (TpAccountManagerPrivate));
- object_class->constructed = tp_account_manager_constructed;
+ object_class->constructed = _tp_account_manager_constructed;
+ object_class->finalize = _tp_account_manager_finalize;
+ object_class->dispose = _tp_account_manager_dispose;
proxy_class->interface = TP_IFACE_QUARK_ACCOUNT_MANAGER;
tp_account_manager_init_known_interfaces ();
+
+ /**
+ * TpAccountManager::account-validity-changed:
+ * @manager: a #TpAccountManager
+ * @account: a #TpAccount
+ * @valid: %TRUE if the account is now valid
+ *
+ * Emitted when the validity on @account changes. @account is not guaranteed
+ * to be ready when this signal is emitted.
+ *
+ * Since: 0.9.0
+ */
+ signals[ACCOUNT_VALIDITY_CHANGED] = g_signal_new ("account-validity-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ _tp_marshal_VOID__OBJECT_BOOLEAN,
+ G_TYPE_NONE,
+ 2, TP_TYPE_ACCOUNT, G_TYPE_BOOLEAN);
+
+ /**
+ * TpAccountManager::account-removed:
+ * @manager: a #TpAccountManager
+ * @account: a #TpAccount
+ *
+ * Emitted when an account is removed from @manager.
+ *
+ * Since: 0.9.0
+ */
+ signals[ACCOUNT_REMOVED] = g_signal_new ("account-removed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1, TP_TYPE_ACCOUNT);
+
+ /**
+ * TpAccountManager::account-enabled:
+ * @manager: a #TpAccountManager
+ * @account: a #TpAccount
+ *
+ * Emitted when an account from @manager is enabled.
+ *
+ * Note that the returned #TpAccount @account is not guaranteed to have any
+ * features pre-prepared, including %TP_ACCOUNT_FEATURE_CORE.
+ *
+ * Since: 0.9.0
+ */
+ signals[ACCOUNT_ENABLED] = g_signal_new ("account-enabled",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1, TP_TYPE_ACCOUNT);
+
+ /**
+ * TpAccountManager::account-disabled.
+ * @manager: a #TpAccountManager
+ * @account: a #TpAccount
+ *
+ * Emitted when an account from @manager is disabled.
+ *
+ * Since: 0.9.0
+ */
+ signals[ACCOUNT_DISABLED] = g_signal_new ("account-disabled",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1, TP_TYPE_ACCOUNT);
+
+ /**
+ * TpAccountManager::most-available-presence-changed:
+ * @manager: a #TpAccountManager
+ * @account: a #TpAccount
+ * @presence: new presence type
+ * @status: new status
+ * @message: new status message
+ *
+ * Emitted when the most available presence on @manager changes.
+ *
+ * Since: 0.9.0
+ */
+ signals[MOST_AVAILABLE_PRESENCE_CHANGED] =
+ g_signal_new ("most-available-presence-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ _tp_marshal_VOID__UINT_STRING_STRING,
+ G_TYPE_NONE,
+ 3, G_TYPE_UINT, /* Presence type */
+ G_TYPE_STRING, /* status */
+ G_TYPE_STRING); /* stauts message*/
}
/**
@@ -143,7 +807,12 @@ tp_account_manager_init_known_interfaces (void)
* tp_account_manager_new:
* @bus_daemon: Proxy for the D-Bus daemon
*
- * Convenience function to create a new account manager proxy.
+ * Convenience function to create a new account manager proxy. The returned
+ * #TpAccountManager is not guaranteed to be ready on return.
+ *
+ * Use tp_account_manager_dup() instead if you want an account manager proxy
+ * on the starter or session bus (which is almost always the right thing for
+ * Telepathy).
*
* Returns: a new reference to an account manager proxy
*/
@@ -152,14 +821,686 @@ tp_account_manager_new (TpDBusDaemon *bus_daemon)
{
TpAccountManager *self;
- g_return_val_if_fail (bus_daemon != NULL, NULL);
+ g_return_val_if_fail (TP_IS_DBUS_DAEMON (bus_daemon), NULL);
self = TP_ACCOUNT_MANAGER (g_object_new (TP_TYPE_ACCOUNT_MANAGER,
- "dbus-daemon", bus_daemon,
- "dbus-connection", ((TpProxy *) bus_daemon)->dbus_connection,
- "bus-name", TP_ACCOUNT_MANAGER_BUS_NAME,
- "object-path", TP_ACCOUNT_MANAGER_OBJECT_PATH,
- NULL));
+ "dbus-daemon", bus_daemon,
+ "dbus-connection", ((TpProxy *) bus_daemon)->dbus_connection,
+ "bus-name", TP_ACCOUNT_MANAGER_BUS_NAME,
+ "object-path", TP_ACCOUNT_MANAGER_OBJECT_PATH,
+ NULL));
return self;
}
+
+static gpointer starter_account_manager_proxy = NULL;
+
+/**
+ * tp_account_manager_dup:
+ *
+ * Returns an account manager proxy on the D-Bus daemon on which this
+ * process was activated (if it was launched by D-Bus service activation), or
+ * the session bus (otherwise).
+ *
+ * The returned #TpAccountManager is cached; the same #TpAccountManager object
+ * will be returned by this function repeatedly, as long as at least one
+ * reference exists. Note that the returned #TpAccountManager is not guaranteed
+ * to be ready on return.
+ *
+ * Returns: an account manager proxy on the starter or session bus, or %NULL
+ * if it wasn't possible to get a dbus daemon proxy for the
+ * appropriate bus
+ *
+ * Since: 0.9.0
+ */
+TpAccountManager *
+tp_account_manager_dup (void)
+{
+ TpDBusDaemon *dbus;
+
+ if (starter_account_manager_proxy != NULL)
+ return g_object_ref (starter_account_manager_proxy);
+
+ dbus = tp_dbus_daemon_dup (NULL);
+
+ if (dbus == NULL)
+ return NULL;
+
+ starter_account_manager_proxy = tp_account_manager_new (dbus);
+ g_assert (starter_account_manager_proxy != NULL);
+ g_object_add_weak_pointer (starter_account_manager_proxy,
+ &starter_account_manager_proxy);
+
+ return starter_account_manager_proxy;
+}
+
+static void
+_tp_account_manager_account_enabled_cb (TpAccount *account,
+ GParamSpec *spec,
+ gpointer manager)
+{
+ TpAccountManager *self = TP_ACCOUNT_MANAGER (manager);
+
+ if (tp_account_is_enabled (account))
+ g_signal_emit (self, signals[ACCOUNT_ENABLED], 0, account);
+ else
+ g_signal_emit (self, signals[ACCOUNT_DISABLED], 0, account);
+}
+
+static void
+_tp_account_manager_account_presence_changed_cb (TpAccount *account,
+ TpConnectionPresenceType presence,
+ const gchar *status,
+ const gchar *status_message,
+ gpointer user_data)
+{
+ TpAccountManager *manager = TP_ACCOUNT_MANAGER (user_data);
+ TpAccountManagerPrivate *priv = manager->priv;
+
+ if (tp_connection_presence_type_cmp_availability (presence,
+ priv->most_available_presence) > 0)
+ {
+ priv->most_available_account = account;
+
+ priv->most_available_presence = presence;
+
+ g_free (priv->most_available_status);
+ priv->most_available_status = g_strdup (status);
+
+ g_free (priv->most_available_status_message);
+ priv->most_available_status_message = g_strdup (status_message);
+
+ goto signal;
+ }
+ else if (priv->most_available_account == account)
+ {
+ _tp_account_manager_update_most_available_presence (manager);
+ goto signal;
+ }
+
+ return;
+signal:
+ g_signal_emit (manager, signals[MOST_AVAILABLE_PRESENCE_CHANGED], 0,
+ priv->most_available_presence, priv->most_available_status,
+ priv->most_available_status_message);
+}
+
+static void
+_tp_account_manager_account_invalidated_cb (TpProxy *proxy,
+ guint domain,
+ gint code,
+ gchar *message,
+ gpointer user_data)
+{
+ TpAccountManager *manager = TP_ACCOUNT_MANAGER (user_data);
+ TpAccountManagerPrivate *priv = manager->priv;
+ TpAccount *account = TP_ACCOUNT (proxy);
+
+ /* We only want to deal with accounts being removed here. */
+ if (domain != TP_DBUS_ERRORS || code != TP_DBUS_ERROR_OBJECT_REMOVED)
+ return;
+
+ g_object_ref (account);
+ g_hash_table_remove (priv->accounts,
+ tp_proxy_get_object_path (account));
+
+ g_signal_emit (manager, signals[ACCOUNT_REMOVED], 0, account);
+ g_object_unref (account);
+}
+
+static void
+_tp_account_manager_account_ready_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ TpAccountManager *manager = TP_ACCOUNT_MANAGER (user_data);
+ TpAccountManagerPrivate *priv = manager->priv;
+ TpAccount *account = TP_ACCOUNT (source_object);
+ GSimpleAsyncResult *result;
+
+ if (!tp_account_prepare_finish (account, res, NULL))
+ return;
+
+ /* see if there's any pending callbacks for this account */
+ result = g_hash_table_lookup (priv->create_results, account);
+ if (result != NULL)
+ {
+ g_simple_async_result_set_op_res_gpointer (
+ G_SIMPLE_ASYNC_RESULT (result), account, NULL);
+
+ g_simple_async_result_complete (result);
+
+ g_hash_table_remove (priv->create_results, account);
+ g_object_unref (result);
+ }
+
+ g_signal_connect (account, "notify::enabled",
+ G_CALLBACK (_tp_account_manager_account_enabled_cb), manager);
+
+ g_signal_connect (account, "presence-changed",
+ G_CALLBACK (_tp_account_manager_account_presence_changed_cb), manager);
+
+ g_signal_connect (account, "invalidated",
+ G_CALLBACK (_tp_account_manager_account_invalidated_cb), manager);
+
+ _tp_account_manager_check_core_ready (manager);
+}
+
+/**
+ * tp_account_manager_ensure_account:
+ * @manager: a #TpAccountManager
+ * @path: the object path for an account
+ *
+ * Lookup an account in the account manager @manager. If the desired account
+ * has already been ensured then the same object will be returned, otherwise
+ * it will create a new #TpAccount and add it to @manager. As a result, if
+ * @manager thinks that the account doesn't exist, this will still add it to
+ * @manager to avoid races. Note that the returned #TpAccount is not guaranteed
+ * to be ready on return.
+ *
+ * The caller must keep a ref to the returned object using g_object_ref() if
+ * it is to be kept.
+ *
+ * Returns: a new #TpAccount at @path
+ *
+ * Since: 0.9.0
+ */
+TpAccount *
+tp_account_manager_ensure_account (TpAccountManager *manager,
+ const gchar *path)
+{
+ TpAccountManagerPrivate *priv;
+ TpAccount *account;
+ GQuark fs[] = { TP_ACCOUNT_FEATURE_CORE, 0 };
+
+ g_return_val_if_fail (TP_IS_ACCOUNT_MANAGER (manager), NULL);
+ g_return_val_if_fail (path != NULL, NULL);
+
+ priv = manager->priv;
+
+ account = g_hash_table_lookup (priv->accounts, path);
+ if (account != NULL)
+ return account;
+
+ account = tp_account_new (tp_proxy_get_dbus_daemon (manager), path, NULL);
+ g_hash_table_insert (priv->accounts, g_strdup (path), account);
+
+ tp_account_prepare_async (account, fs, _tp_account_manager_account_ready_cb,
+ manager);
+
+ return account;
+}
+
+/**
+ * tp_account_manager_get_valid_accounts:
+ * @manager: a #TpAccountManager
+ *
+ * Returns a newly allocated #GList of valid accounts in @manager. The list
+ * must be freed with g_list_free() after used. None of the accounts in the
+ * returned list are guaranteed to be ready.
+ *
+ * Note that the #TpAccount<!-- -->s in the returned #GList are not reffed
+ * before returning from this function. One could ref every item in the list
+ * like the following example:
+ * |[
+ * GList *accounts;
+ * account = tp_account_manager_get_valid_accounts (manager);
+ * g_list_foreach (accounts, (GFunc) g_object_ref, NULL);
+ * ]|
+ *
+ * The list of valid accounts returned is not guaranteed to have been retrieved
+ * until %TP_ACCOUNT_MANAGER_FEATURE_CORE is prepared
+ * (tp_account_manager_prepare_async() has returned). Until this feature has
+ * been prepared, an empty list (%NULL) will be returned.
+ *
+ * Returns: a newly allocated #GList of valid accounts in @manager
+ *
+ * Since: 0.9.0
+ */
+GList *
+tp_account_manager_get_valid_accounts (TpAccountManager *manager)
+{
+ TpAccountManagerPrivate *priv;
+ GList *ret;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT_MANAGER (manager), NULL);
+
+ priv = manager->priv;
+
+ ret = g_hash_table_get_values (priv->accounts);
+
+ return ret;
+}
+
+/**
+ * tp_account_manager_set_all_requested_presences:
+ * @manager: a #TpAccountManager
+ * @type: a presence type to request
+ * @status: a status to request
+ * @message: a status message to request
+ *
+ * Iterates through the accounts in @manager and requests the presence
+ * (@type, @status and @message). Note that the presence requested here is
+ * merely a request, and if might not be satisfiable.
+ *
+ * You can find the most available presence across all accounts by calling
+ * tp_account_manager_get_most_available_presence().
+ *
+ * Setting a requested presence on all accounts will have no effect
+ * until tp_account_manager_prepare_async() has finished.
+ *
+ * Since: 0.9.0
+ */
+void
+tp_account_manager_set_all_requested_presences (TpAccountManager *manager,
+ TpConnectionPresenceType type,
+ const gchar *status,
+ const gchar *message)
+{
+ TpAccountManagerPrivate *priv;
+ GHashTableIter iter;
+ gpointer value;
+
+ g_return_if_fail (TP_IS_ACCOUNT_MANAGER (manager));
+
+ priv = manager->priv;
+
+ DEBUG ("request most available presence, type: %d, status: %s, message: %s",
+ type, status, message);
+
+ g_hash_table_iter_init (&iter, priv->accounts);
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ TpAccount *account = TP_ACCOUNT (value);
+
+ if (tp_account_is_prepared (account, TP_ACCOUNT_FEATURE_CORE))
+ tp_account_request_presence_async (account, type, status, message,
+ NULL, NULL);
+ }
+
+ /* save the requested presence, to use it in case we create new accounts or
+ * some accounts become ready. */
+ priv->requested_presence = type;
+
+ if (tp_strdiff (priv->requested_status, status))
+ {
+ g_free (priv->requested_status);
+ priv->requested_status = g_strdup (status);
+ }
+
+ if (tp_strdiff (priv->requested_status_message, message))
+ {
+ g_free (priv->requested_status_message);
+ priv->requested_status_message = g_strdup (message);
+ }
+}
+
+/**
+ * tp_account_manager_get_most_available_presence:
+ * @manager: a #TpAccountManager
+ * @status: a string to fill with the actual status
+ * @message: a string to fill with the actual status message
+ *
+ * Gets the most available presence over all accounts in @manager. This
+ * function does not average presences across all accounts, but it merely
+ * finds the "most available" presence. As a result, there is a guarantee
+ * that there exists at least one account in @manager with the returned
+ * presence.
+ *
+ * If no accounts are enabled or valid the output will be
+ * (%TP_CONNECTION_PRESENCE_TYPE_OFFLINE, "offline", "").
+ *
+ * The return value of this function is not guaranteed to have been retrieved
+ * until tp_account_manager_prepare_async() has finished; until then, the
+ * value will be the same as if no accounts are enabled or valid.
+ *
+ * Returns: the most available presence across all accounts
+ *
+ * Since: 0.9.0
+ */
+
+TpConnectionPresenceType
+tp_account_manager_get_most_available_presence (TpAccountManager *manager,
+ gchar **status,
+ gchar **message)
+{
+ TpAccountManagerPrivate *priv;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT_MANAGER (manager),
+ TP_CONNECTION_PRESENCE_TYPE_UNSET);
+
+ priv = manager->priv;
+
+ if (status != NULL)
+ *status = g_strdup (priv->most_available_status);
+
+ if (message != NULL)
+ *message = g_strdup (priv->most_available_status_message);
+
+ return priv->most_available_presence;
+}
+
+static void
+_tp_account_manager_created_cb (TpAccountManager *proxy,
+ const gchar *account_path,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ TpAccountManager *manager = TP_ACCOUNT_MANAGER (weak_object);
+ TpAccountManagerPrivate *priv = manager->priv;
+ GSimpleAsyncResult *my_res = user_data;
+ TpAccount *account;
+
+ if (error != NULL)
+ {
+ g_simple_async_result_set_from_error (my_res, (GError *) error);
+ g_simple_async_result_complete (my_res);
+ g_object_unref (my_res);
+
+ return;
+ }
+
+ account = tp_account_manager_ensure_account (manager, account_path);
+
+ g_hash_table_insert (priv->create_results, account, my_res);
+}
+
+/**
+ * tp_account_manager_create_account_async:
+ * @manager: a #TpAccountManager
+ * @connection_manager: the name of a connection manager
+ * @protocol: the name of a protocol
+ * @display_name: the display name for the account
+ * @parameters: parameters for the new account
+ * @properties: properties for the new account
+ * @callback: a callback to call when the request is satisfied
+ * @user_data: data to pass to @callback
+ *
+ * Requests an asynchronous create of an account on the account manager
+ * @manager. When the operation is finished, @callback will be called. You can
+ * then call tp_account_manager_create_account_finish() to get the result of
+ * the operation.
+ *
+ * @callback will only be called when the newly created #TpAccount has the
+ * %TP_ACCOUNT_FEATURE_CORE feature ready on it, so when calling
+ * tp_account_manager_create_account_finish(), one can guarantee this feature
+ * will be ready.
+ *
+ * Since: 0.9.0
+ */
+void
+tp_account_manager_create_account_async (TpAccountManager *manager,
+ const gchar *connection_manager,
+ const gchar *protocol,
+ const gchar *display_name,
+ GHashTable *parameters,
+ GHashTable *properties,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+
+ g_return_if_fail (TP_IS_ACCOUNT_MANAGER (manager));
+ g_return_if_fail (connection_manager != NULL);
+ g_return_if_fail (protocol != NULL);
+ g_return_if_fail (display_name != NULL);
+ g_return_if_fail (parameters != NULL);
+ g_return_if_fail (properties != NULL);
+ g_return_if_fail (TP_IS_ACCOUNT_MANAGER (manager));
+
+ res = g_simple_async_result_new (G_OBJECT (manager), callback, user_data,
+ tp_account_manager_create_account_finish);
+
+ tp_cli_account_manager_call_create_account (manager,
+ -1, connection_manager, protocol, display_name, parameters,
+ properties, _tp_account_manager_created_cb, res, NULL,
+ G_OBJECT (manager));
+}
+
+/**
+ * tp_account_manager_create_account_finish:
+ * @manager: a #TpAccountManager
+ * @result: a #GAsyncResult
+ * @error: a #GError to be filled
+ *
+ * Finishes an async create account operation, and returns a new #TpAccount
+ * object, with the %TP_ACCOUNT_FEATURE_CORE feature ready on it.
+ *
+ * Returns: a new #TpAccount which was just created on success, otherwise
+ * %NULL
+ *
+ * Since: 0.9.0
+ */
+TpAccount *
+tp_account_manager_create_account_finish (TpAccountManager *manager,
+ GAsyncResult *result,
+ GError **error)
+{
+ TpAccount *retval;
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT_MANAGER (manager), NULL);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
+ error))
+ return NULL;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (manager), tp_account_manager_create_account_finish), NULL);
+
+ retval = TP_ACCOUNT (g_simple_async_result_get_op_res_gpointer (
+ G_SIMPLE_ASYNC_RESULT (result)));
+
+ return retval;
+}
+
+/**
+ * tp_account_manager_is_prepared:
+ * @manager: a #TpAccountManager
+ * @feature: a feature which is required
+ * @error: a #GError to fill
+ *
+ * <!-- -->
+ *
+ * Returns: %TRUE whether @feature is ready on @manager, otherwise %FALSE
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_manager_is_prepared (TpAccountManager *manager,
+ GQuark feature)
+{
+ TpAccountManagerFeature *f;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT_MANAGER (manager), FALSE);
+
+ if (tp_proxy_get_invalidated (manager) != NULL)
+ return FALSE;
+
+ f = _tp_account_manager_get_feature (manager, feature);
+
+ if (f == NULL)
+ return FALSE;
+
+ return f->ready;
+}
+
+/**
+ * tp_account_manager_prepare_async:
+ * @manager: a #TpAccountManager
+ * @features: a 0-terminated list of features, or %NULL
+ * @callback: a callback to call when the request is satisfied
+ * @user_data: data to pass to @callback
+ *
+ * Requests an asynchronous preparation of @manager with the features specified
+ * by @features. When the operation is finished, @callback will be called. You
+ * can then call tp_account_manager_prepare_finish() to get the result of the
+ * operation.
+ *
+ * If @features is %NULL, then @callback will be called when the implied
+ * %TP_ACCOUNT_FEATURE_CORE feature is ready.
+ *
+ * If %NULL is given to @callback, then no callback will be called when the
+ * operation is finished. Instead, it will simply set @features on @manager.
+ * Note that if @callback is %NULL, then @user_data must also be %NULL.
+ *
+ * Since: 0.9.0
+ */
+void
+tp_account_manager_prepare_async (TpAccountManager *manager,
+ const GQuark *features,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ TpAccountManagerPrivate *priv;
+ GSimpleAsyncResult *result;
+ const GQuark *f;
+
+ g_return_if_fail (TP_IS_ACCOUNT_MANAGER (manager));
+
+ priv = manager->priv;
+
+ /* In this object, there are no features which are activatable (core is
+ * forced on you). They'd be activated here though. */
+
+ for (f = features; f != NULL && *f != 0; f++)
+ {
+ /* Only add features to requested which exist on this object and are not
+ * already in the list. */
+ if (_tp_account_manager_get_feature (manager, *f) != NULL
+ && _tp_account_manager_feature_in_array (*f, priv->requested_features))
+ g_array_append_val (priv->requested_features, *f);
+ }
+
+ if (callback == NULL)
+ return;
+
+ result = g_simple_async_result_new (G_OBJECT (manager),
+ callback, user_data, tp_account_manager_prepare_finish);
+
+ if (_tp_account_manager_check_features (manager, features))
+ {
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+ }
+ else
+ {
+ TpAccountManagerFeatureCallback *cb;
+
+ cb = g_slice_new0 (TpAccountManagerFeatureCallback);
+ cb->result = result;
+ cb->features = features;
+ priv->callbacks = g_list_prepend (priv->callbacks, cb);
+ }
+}
+
+/**
+ * tp_account_manager_prepare_finish:
+ * @manager: a #TpAccountManager
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Finishes an async preparation of the account manager @manager.
+ *
+ * Returns: %TRUE if the preparation was successful, otherwise %FALSE
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_manager_prepare_finish (TpAccountManager *manager,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT_MANAGER (manager), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (manager),tp_account_manager_prepare_finish), FALSE);
+
+ return TRUE;
+}
+
+/**
+ * _tp_account_manager_get_requested_features:
+ * @manager: a #TpAccountManager
+ *
+ * <!-- -->
+ *
+ * Returns: a 0-terminated list of requested features on @manager
+ *
+ * Since: 0.9.0
+ */
+const GQuark *
+_tp_account_manager_get_requested_features (TpAccountManager *manager)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT_MANAGER (manager), NULL);
+
+ return (const GQuark *) manager->priv->requested_features->data;
+}
+
+/**
+ * _tp_account_manager_get_actual_features:
+ * @manager: a #TpAccountManager
+ *
+ * <!-- -->
+ *
+ * Returns: a 0-terminated list of actual features on @manager
+ *
+ * Since: 0.9.0
+ */
+const GQuark *
+_tp_account_manager_get_actual_features (TpAccountManager *manager)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT_MANAGER (manager), NULL);
+
+ return (const GQuark *) manager->priv->actual_features->data;
+}
+
+/**
+ * _tp_account_manager_get_missing_features:
+ * @manager: a #TpAccountManager
+ *
+ * <!-- -->
+ *
+ * Returns: a 0-terminated list of missing features on @manager
+ *
+ * Since: 0.9.0
+ */
+const GQuark *
+_tp_account_manager_get_missing_features (TpAccountManager *manager)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT_MANAGER (manager), NULL);
+
+ return (const GQuark *) manager->priv->missing_features->data;
+}
+
+/**
+ * tp_account_manager_enable_restart:
+ * @manager: a #TpAccountManager
+ *
+ * Enable autostarting the account manager D-Bus service. This means
+ * that the account manager will be restarted if it disappears from
+ * the bus.
+ */
+void
+tp_account_manager_enable_restart (TpAccountManager *manager)
+{
+ g_return_if_fail (TP_IS_ACCOUNT_MANAGER (manager));
+
+ tp_dbus_daemon_watch_name_owner (tp_proxy_get_dbus_daemon (manager),
+ TP_ACCOUNT_MANAGER_BUS_NAME, _tp_account_manager_name_owner_cb,
+ manager, NULL);
+
+ _tp_account_manager_start_mc5 (tp_proxy_get_dbus_daemon (manager));
+}
diff --git a/telepathy-glib/account-manager.h b/telepathy-glib/account-manager.h
index f96321ac7..f117cd2f4 100644
--- a/telepathy-glib/account-manager.h
+++ b/telepathy-glib/account-manager.h
@@ -22,6 +22,7 @@
#ifndef TP_ACCOUNT_MANAGER_H
#define TP_ACCOUNT_MANAGER_H
+#include <telepathy-glib/account.h>
#include <telepathy-glib/proxy.h>
#include <telepathy-glib/dbus.h>
@@ -63,10 +64,47 @@ GType tp_account_manager_get_type (void);
(G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TYPE_ACCOUNT_MANAGER, \
TpAccountManagerClass))
+#define TP_ACCOUNT_MANAGER_FEATURE_CORE \
+ tp_account_manager_get_feature_quark_core ()
+
+GQuark tp_account_manager_get_feature_quark_core (void) G_GNUC_CONST;
+
TpAccountManager *tp_account_manager_new (TpDBusDaemon *bus_daemon);
+TpAccountManager *tp_account_manager_dup (void);
+
void tp_account_manager_init_known_interfaces (void);
+TpAccount *tp_account_manager_ensure_account (TpAccountManager *manager,
+ const gchar *path);
+
+GList *tp_account_manager_get_valid_accounts (TpAccountManager *manager);
+
+void tp_account_manager_set_all_requested_presences (TpAccountManager *manager,
+ TpConnectionPresenceType type, const gchar *status, const gchar *message);
+
+TpConnectionPresenceType tp_account_manager_get_most_available_presence (
+ TpAccountManager *manager, gchar **status, gchar **message);
+
+void tp_account_manager_create_account_async (TpAccountManager *manager,
+ const gchar *connection_manager, const gchar *protocol,
+ const gchar *display_name, GHashTable *parameters, GHashTable *properties,
+ GAsyncReadyCallback callback, gpointer user_data);
+
+TpAccount * tp_account_manager_create_account_finish (
+ TpAccountManager *manager, GAsyncResult *result, GError **error);
+
+gboolean tp_account_manager_is_prepared (TpAccountManager *manager,
+ GQuark feature);
+
+void tp_account_manager_prepare_async (TpAccountManager *manager,
+ const GQuark *features, GAsyncReadyCallback callback, gpointer user_data);
+
+gboolean tp_account_manager_prepare_finish (TpAccountManager *manager,
+ GAsyncResult *result, GError **error);
+
+void tp_account_manager_enable_restart (TpAccountManager *manager);
+
G_END_DECLS
#include <telepathy-glib/_gen/tp-cli-account-manager.h>
diff --git a/telepathy-glib/account.c b/telepathy-glib/account.c
index 3285c5991..830e29534 100644
--- a/telepathy-glib/account.c
+++ b/telepathy-glib/account.c
@@ -19,17 +19,23 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <string.h>
+
+#include "telepathy-glib/account-internal.h"
#include "telepathy-glib/account.h"
#include <telepathy-glib/dbus.h>
#include <telepathy-glib/defs.h>
#include <telepathy-glib/errors.h>
+#include <telepathy-glib/gtypes.h>
#include <telepathy-glib/interfaces.h>
#include <telepathy-glib/proxy-subclass.h>
+#include <telepathy-glib/util.h>
#define DEBUG_FLAG TP_DEBUG_ACCOUNTS
#include "telepathy-glib/debug-internal.h"
+#include "telepathy-glib/_gen/signals-marshal.h"
#include "telepathy-glib/_gen/tp-cli-account-body.h"
/**
@@ -56,19 +62,9 @@
* with the domain %TP_DBUS_ERRORS and the error code
* %TP_DBUS_ERROR_OBJECT_REMOVED.
*
- * This proxy is usable but very incomplete: accessors for the
- * Account's D-Bus properties will be added in a later version of
- * telepathy-glib, along with a mechanism similar to
- * tp_connection_call_when_ready().
- *
- * Most operations performed on an Account are done via D-Bus properties.
- * Until convenience methods for this are implemented, use of the generic
- * tp_cli_dbus_properties_call_get_all() and tp_cli_dbus_properties_call_set()
- * methods is recommended.
- *
- * Other useful auto-generated method wrappers on an Account include
- * tp_cli_account_call_remove(), tp_cli_account_call_update_parameters() and
- * tp_cli_account_call_reconnect().
+ * One can connect to the #GObject::notify signal to get change notifications
+ * for many of the properties on this object. Refer to each property's
+ * documentation for whether it can be used in this way.
*
* Since: 0.7.32
*/
@@ -80,56 +76,728 @@
*/
struct _TpAccountPrivate {
- gpointer dummy;
+ gboolean dispose_has_run;
+
+ TpConnection *connection;
+ gchar *connection_object_path;
+
+ TpConnectionStatus connection_status;
+ TpConnectionStatusReason reason;
+
+ TpConnectionPresenceType presence;
+ gchar *status;
+ gchar *message;
+
+ TpConnectionPresenceType requested_presence;
+ gchar *requested_status;
+ gchar *requested_message;
+
+ gboolean connect_automatically;
+ gboolean has_been_online;
+
+ gchar *nickname;
+
+ gboolean enabled;
+ gboolean valid;
+ gboolean removed;
+
+ gchar *cm_name;
+ gchar *proto_name;
+ gchar *icon_name;
+
+ gchar *display_name;
+
+ GHashTable *parameters;
+
+ /* Features. */
+ GList *features;
+ GList *callbacks;
+ GArray *requested_features;
+ GArray *actual_features;
+ GArray *missing_features;
};
+typedef struct {
+ GQuark name;
+ gboolean ready;
+} TpAccountFeature;
+
+typedef struct {
+ GSimpleAsyncResult *result;
+ const GQuark *features;
+} TpAccountFeatureCallback;
+
G_DEFINE_TYPE (TpAccount, tp_account, TP_TYPE_PROXY);
+/* signals */
+enum {
+ STATUS_CHANGED,
+ PRESENCE_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+/* properties */
+enum {
+ PROP_ENABLED = 1,
+ PROP_CURRENT_PRESENCE_TYPE,
+ PROP_CURRENT_STATUS,
+ PROP_CURRENT_STATUS_MESSAGE,
+ PROP_CONNECTION_STATUS,
+ PROP_CONNECTION_STATUS_REASON,
+ PROP_CONNECTION,
+ PROP_DISPLAY_NAME,
+ PROP_CONNECTION_MANAGER,
+ PROP_PROTOCOL,
+ PROP_ICON_NAME,
+ PROP_CONNECT_AUTOMATICALLY,
+ PROP_HAS_BEEN_ONLINE,
+ PROP_VALID,
+ PROP_REQUESTED_PRESENCE_TYPE,
+ PROP_REQUESTED_STATUS,
+ PROP_REQUESTED_STATUS_MESSAGE,
+ PROP_NICKNAME
+};
+
+/**
+ * TP_ACCOUNT_FEATURE_CORE:
+ *
+ * Expands to a call to a function that returns a quark for the "core" feature
+ * on a #TpAccount.
+ *
+ * When this feature is prepared, the basic properties of the Account have
+ * been retrieved and are available for use, and change-notification has been
+ * set up.
+ *
+ * One can ask for a feature to be prepared using the
+ * tp_account_prepare_async() function, and waiting for it to callback.
+ *
+ * Since: 0.9.0
+ */
+
+/**
+ * tp_account_get_feature_quark_core:
+ *
+ * <!-- -->
+ *
+ * Returns: the quark used for representing the core feature of a
+ * #TpAccount
+ *
+ * Since: 0.9.0
+ */
+GQuark
+tp_account_get_feature_quark_core (void)
+{
+ return g_quark_from_static_string ("tp-account-feature-core");
+}
+
+static const GQuark *
+_tp_account_get_known_features (void)
+{
+ static GQuark features[1] = { 0 };
+
+ if (G_UNLIKELY (features[0] == 0))
+ {
+ features[0] = TP_ACCOUNT_FEATURE_CORE;
+ }
+
+ return features;
+}
+
static void
tp_account_init (TpAccount *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TYPE_ACCOUNT,
TpAccountPrivate);
+
+ self->priv->connection_status = TP_CONNECTION_STATUS_DISCONNECTED;
+}
+
+static TpAccountFeature *
+_tp_account_get_feature (TpAccount *self,
+ GQuark feature)
+{
+ TpAccountPrivate *priv = self->priv;
+ GList *l;
+
+ for (l = priv->features; l != NULL; l = l->next)
+ {
+ TpAccountFeature *f = l->data;
+
+ if (f->name == feature)
+ return f;
+ }
+
+ return NULL;
+}
+
+static gboolean
+_tp_account_feature_in_array (GQuark feature,
+ const GArray *array)
+{
+ const GQuark *c = (const GQuark *) array->data;
+
+ for (; *c != 0; c++)
+ {
+ if (*c == feature)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+_tp_account_check_features (TpAccount *self,
+ const GQuark *features)
+{
+ const GQuark *f;
+ TpAccountFeature *feat;
+
+ for (f = features; f != NULL && *f != 0; f++)
+ {
+ feat = _tp_account_get_feature (self, *f);
+
+ /* features which are NULL (ie. don't exist) are always considered as
+ * being ready, except in _is_prepared when it doesn't make sense to
+ * return TRUE. */
+ if (feat != NULL && !feat->ready)
+ return FALSE;
+ }
+
+ /* Special-case core: no other feature is ready unless core itself is
+ * ready. */
+ feat = _tp_account_get_feature (self, TP_ACCOUNT_FEATURE_CORE);
+ if (!feat->ready)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+_tp_account_become_ready (TpAccount *self,
+ GQuark feature)
+{
+ TpAccountPrivate *priv = self->priv;
+ TpAccountFeature *f = NULL;
+ GList *l, *remove = NULL;
+
+ f = _tp_account_get_feature (self, feature);
+
+ g_assert (f != NULL);
+
+ if (f->ready)
+ return;
+
+ f->ready = TRUE;
+
+ if (!_tp_account_feature_in_array (feature, priv->actual_features))
+ g_array_append_val (priv->actual_features, feature);
+
+ /* First, find which callbacks are satisfied and add those items
+ * from the remove list. */
+ l = priv->callbacks;
+ while (l != NULL)
+ {
+ GList *c = l;
+ TpAccountFeatureCallback *cb = l->data;
+
+ l = l->next;
+
+ if (_tp_account_check_features (self, cb->features))
+ {
+ priv->callbacks = g_list_remove_link (priv->callbacks, c);
+ remove = g_list_concat (c, remove);
+ }
+ }
+
+ /* Next, complete these callbacks */
+ for (l = remove; l != NULL; l = l->next)
+ {
+ TpAccountFeatureCallback *cb = l->data;
+
+ g_simple_async_result_complete (cb->result);
+ g_object_unref (cb->result);
+ g_slice_free (TpAccountFeatureCallback, cb);
+ }
+
+ g_list_free (remove);
}
static void
-tp_account_removed_cb (TpAccount *self,
+_tp_account_removed_cb (TpAccount *self,
gpointer unused G_GNUC_UNUSED,
GObject *object G_GNUC_UNUSED)
{
GError e = { TP_DBUS_ERRORS, TP_DBUS_ERROR_OBJECT_REMOVED,
- "Account removed" };
+ "Account removed" };
+
+ if (self->priv->removed)
+ return;
+
+ self->priv->removed = TRUE;
tp_proxy_invalidate ((TpProxy *) self, &e);
}
static void
-tp_account_constructed (GObject *object)
+_tp_account_free_connection (TpAccount *account)
+{
+ TpAccountPrivate *priv = account->priv;
+
+ if (priv->connection == NULL)
+ return;
+
+ g_object_unref (priv->connection);
+ priv->connection = NULL;
+}
+
+static void
+_tp_account_set_connection (TpAccount *account,
+ const gchar *path)
+{
+ TpAccountPrivate *priv = account->priv;
+
+ if (priv->connection != NULL)
+ {
+ const gchar *current;
+
+ current = tp_proxy_get_object_path (priv->connection);
+ if (!tp_strdiff (current, path))
+ return;
+ }
+
+ _tp_account_free_connection (account);
+
+ if (tp_strdiff ("/", path))
+ {
+ GError *error = NULL;
+ priv->connection = tp_connection_new (tp_proxy_get_dbus_daemon (account),
+ NULL, path, &error);
+
+ if (priv->connection == NULL)
+ {
+ DEBUG ("Failed to create a new TpConnection: %s",
+ error->message);
+ g_error_free (error);
+ }
+ }
+
+ g_object_notify (G_OBJECT (account), "connection");
+}
+
+static void
+_tp_account_update (TpAccount *account,
+ GHashTable *properties)
+{
+ TpAccountPrivate *priv = account->priv;
+ GValueArray *arr;
+ TpConnectionStatus old_s = priv->connection_status;
+ gboolean presence_changed = FALSE;
+
+ if (g_hash_table_lookup (properties, "ConnectionStatus") != NULL)
+ priv->connection_status =
+ tp_asv_get_uint32 (properties, "ConnectionStatus", NULL);
+
+
+ if (g_hash_table_lookup (properties, "ConnectionStatusReason") != NULL)
+ priv->reason = tp_asv_get_int32 (properties,
+ "ConnectionStatusReason", NULL);
+
+ if (g_hash_table_lookup (properties, "CurrentPresence") != NULL)
+ {
+ presence_changed = TRUE;
+ arr = tp_asv_get_boxed (properties, "CurrentPresence",
+ TP_STRUCT_TYPE_SIMPLE_PRESENCE);
+ priv->presence = g_value_get_uint (g_value_array_get_nth (arr, 0));
+
+ g_free (priv->status);
+ priv->status = g_value_dup_string (g_value_array_get_nth (arr, 1));
+
+ g_free (priv->message);
+ priv->message = g_value_dup_string (g_value_array_get_nth (arr, 2));
+ }
+
+ if (g_hash_table_lookup (properties, "RequestedPresence") != NULL)
+ {
+ arr = tp_asv_get_boxed (properties, "RequestedPresence",
+ TP_STRUCT_TYPE_SIMPLE_PRESENCE);
+ priv->requested_presence =
+ g_value_get_uint (g_value_array_get_nth (arr, 0));
+
+ g_free (priv->requested_status);
+ priv->requested_status =
+ g_value_dup_string (g_value_array_get_nth (arr, 1));
+
+ g_free (priv->requested_message);
+ priv->requested_message =
+ g_value_dup_string (g_value_array_get_nth (arr, 2));
+ }
+
+ if (g_hash_table_lookup (properties, "DisplayName") != NULL)
+ {
+ gchar *old = priv->display_name;
+
+ priv->display_name =
+ g_strdup (tp_asv_get_string (properties, "DisplayName"));
+
+ if (tp_strdiff (old, priv->display_name))
+ g_object_notify (G_OBJECT (account), "display-name");
+
+ g_free (old);
+ }
+
+ if (g_hash_table_lookup (properties, "Nickname") != NULL)
+ {
+ gchar *old = priv->nickname;
+
+ priv->nickname = g_strdup (tp_asv_get_string (properties, "Nickname"));
+
+ if (tp_strdiff (old, priv->nickname))
+ g_object_notify (G_OBJECT (account), "nickname");
+
+ g_free (old);
+ }
+
+ if (g_hash_table_lookup (properties, "Icon") != NULL)
+ {
+ const gchar *icon_name;
+ gchar *old = priv->icon_name;
+
+ icon_name = tp_asv_get_string (properties, "Icon");
+
+ if (icon_name == NULL || icon_name[0] == '\0')
+ priv->icon_name = g_strdup_printf ("im-%s", priv->proto_name);
+ else
+ priv->icon_name = g_strdup (icon_name);
+
+ if (tp_strdiff (old, priv->icon_name))
+ g_object_notify (G_OBJECT (account), "icon-name");
+
+ g_free (old);
+ }
+
+ if (g_hash_table_lookup (properties, "Enabled") != NULL)
+ {
+ gboolean enabled = tp_asv_get_boolean (properties, "Enabled", NULL);
+ if (priv->enabled != enabled)
+ {
+ priv->enabled = enabled;
+ g_object_notify (G_OBJECT (account), "enabled");
+ }
+ }
+
+ if (g_hash_table_lookup (properties, "Valid") != NULL)
+ {
+ gboolean old = priv->valid;
+
+ priv->valid = tp_asv_get_boolean (properties, "Valid", NULL);
+
+ if (old != priv->valid)
+ g_object_notify (G_OBJECT (account), "valid");
+ }
+
+ if (g_hash_table_lookup (properties, "Parameters") != NULL)
+ {
+ GHashTable *parameters;
+
+ parameters = tp_asv_get_boxed (properties, "Parameters",
+ TP_HASH_TYPE_STRING_VARIANT_MAP);
+
+ if (priv->parameters != NULL)
+ g_hash_table_unref (priv->parameters);
+
+ priv->parameters = g_boxed_copy (TP_HASH_TYPE_STRING_VARIANT_MAP,
+ parameters);
+ }
+
+ if (priv->connection_status != old_s)
+ {
+ g_signal_emit (account, signals[STATUS_CHANGED], 0,
+ old_s, priv->connection_status, priv->reason, NULL, NULL);
+
+ g_object_notify (G_OBJECT (account), "connection-status");
+ g_object_notify (G_OBJECT (account), "connection-status-reason");
+ }
+
+ if (presence_changed)
+ {
+ g_signal_emit (account, signals[PRESENCE_CHANGED], 0,
+ priv->presence, priv->status, priv->message);
+ g_object_notify (G_OBJECT (account), "current-presence-type");
+ g_object_notify (G_OBJECT (account), "current-status");
+ g_object_notify (G_OBJECT (account), "current-status-message");
+ }
+
+ if (g_hash_table_lookup (properties, "Connection") != NULL)
+ {
+ g_free (priv->connection_object_path);
+
+ priv->connection_object_path =
+ g_strdup (tp_asv_get_object_path (properties, "Connection"));
+
+ if (priv->connection != NULL)
+ {
+ if (tp_strdiff (priv->connection_object_path,
+ tp_proxy_get_object_path (priv->connection)))
+ _tp_account_free_connection (account);
+ }
+ }
+
+ if (g_hash_table_lookup (properties, "ConnectAutomatically") != NULL)
+ {
+ gboolean old = priv->connect_automatically;
+
+ priv->connect_automatically =
+ tp_asv_get_boolean (properties, "ConnectAutomatically", NULL);
+
+ if (old != priv->connect_automatically)
+ g_object_notify (G_OBJECT (account), "connect-automatically");
+ }
+
+ if (g_hash_table_lookup (properties, "HasBeenOnline") != NULL)
+ {
+ gboolean old = priv->has_been_online;
+
+ priv->has_been_online =
+ tp_asv_get_boolean (properties, "HasBeenOnline", NULL);
+
+ if (old != priv->has_been_online)
+ g_object_notify (G_OBJECT (account), "has-been-online");
+ }
+
+ _tp_account_become_ready (account, TP_ACCOUNT_FEATURE_CORE);
+}
+
+static void
+_tp_account_properties_changed (TpAccount *proxy,
+ GHashTable *properties,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ TpAccount *self = TP_ACCOUNT (weak_object);
+
+ if (!tp_account_is_prepared (self, TP_ACCOUNT_FEATURE_CORE))
+ return;
+
+ _tp_account_update (self, properties);
+}
+
+static void
+_tp_account_got_all_cb (TpProxy *proxy,
+ GHashTable *properties,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ TpAccount *self = TP_ACCOUNT (weak_object);
+
+ DEBUG ("Got whole set of properties for %s",
+ tp_proxy_get_object_path (self));
+
+ if (error != NULL)
+ {
+ DEBUG ("Failed to get the initial set of account properties: %s",
+ error->message);
+ return;
+ }
+
+ _tp_account_update (self, properties);
+}
+
+static void
+_tp_account_constructed (GObject *object)
{
TpAccount *self = TP_ACCOUNT (object);
+ TpAccountPrivate *priv = self->priv;
void (*chain_up) (GObject *) =
((GObjectClass *) tp_account_parent_class)->constructed;
GError *error = NULL;
TpProxySignalConnection *sc;
+ guint i;
+ const GQuark *known_features;
if (chain_up != NULL)
chain_up (object);
g_return_if_fail (tp_proxy_get_dbus_daemon (self) != NULL);
- sc = tp_cli_account_connect_to_removed (self, tp_account_removed_cb,
+ priv->features = NULL;
+ priv->callbacks = NULL;
+ priv->requested_features = g_array_new (TRUE, FALSE, sizeof (GQuark));
+ priv->actual_features = g_array_new (TRUE, FALSE, sizeof (GQuark));
+ priv->missing_features = g_array_new (TRUE, FALSE, sizeof (GQuark));
+
+ known_features = _tp_account_get_known_features ();
+
+ /* Fill features list */
+ for (i = 0; i < G_N_ELEMENTS (known_features); i++)
+ {
+ TpAccountFeature *feature;
+ feature = g_slice_new0 (TpAccountFeature);
+ feature->name = known_features[i];
+ feature->ready = FALSE;
+ priv->features = g_list_prepend (priv->features, feature);
+ }
+
+ sc = tp_cli_account_connect_to_removed (self, _tp_account_removed_cb,
NULL, NULL, NULL, &error);
if (sc == NULL)
{
g_critical ("Couldn't connect to Removed: %s", error->message);
g_error_free (error);
- g_assert_not_reached ();
- return;
+ }
+
+ tp_account_parse_object_path (tp_proxy_get_object_path (self),
+ &(priv->cm_name), &(priv->proto_name), NULL, NULL);
+
+ priv->icon_name = g_strdup_printf ("im-%s", priv->proto_name);
+
+ tp_cli_account_connect_to_account_property_changed (self,
+ _tp_account_properties_changed, NULL, NULL, object, NULL);
+
+ tp_cli_dbus_properties_call_get_all (self, -1, TP_IFACE_ACCOUNT,
+ _tp_account_got_all_cb, NULL, NULL, G_OBJECT (self));
+}
+
+static void
+_tp_account_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TpAccount *self = TP_ACCOUNT (object);
+
+ switch (prop_id)
+ {
+ case PROP_ENABLED:
+ g_value_set_boolean (value, self->priv->enabled);
+ break;
+ case PROP_CURRENT_PRESENCE_TYPE:
+ g_value_set_uint (value, self->priv->presence);
+ break;
+ case PROP_CURRENT_STATUS:
+ g_value_set_string (value, self->priv->status);
+ break;
+ case PROP_CURRENT_STATUS_MESSAGE:
+ g_value_set_string (value, self->priv->message);
+ break;
+ case PROP_CONNECTION_STATUS:
+ g_value_set_uint (value, self->priv->connection_status);
+ break;
+ case PROP_CONNECTION_STATUS_REASON:
+ g_value_set_uint (value, self->priv->reason);
+ break;
+ case PROP_CONNECTION:
+ g_value_set_object (value,
+ tp_account_get_connection (self));
+ break;
+ case PROP_DISPLAY_NAME:
+ g_value_set_string (value,
+ tp_account_get_display_name (self));
+ break;
+ case PROP_CONNECTION_MANAGER:
+ g_value_set_string (value, self->priv->cm_name);
+ break;
+ case PROP_PROTOCOL:
+ g_value_set_string (value, self->priv->proto_name);
+ break;
+ case PROP_ICON_NAME:
+ g_value_set_string (value, self->priv->icon_name);
+ break;
+ case PROP_CONNECT_AUTOMATICALLY:
+ g_value_set_boolean (value, self->priv->connect_automatically);
+ break;
+ case PROP_HAS_BEEN_ONLINE:
+ g_value_set_boolean (value, self->priv->has_been_online);
+ break;
+ case PROP_VALID:
+ g_value_set_boolean (value, self->priv->valid);
+ break;
+ case PROP_REQUESTED_PRESENCE_TYPE:
+ g_value_set_uint (value, self->priv->requested_presence);
+ break;
+ case PROP_REQUESTED_STATUS:
+ g_value_set_string (value, self->priv->requested_status);
+ break;
+ case PROP_REQUESTED_STATUS_MESSAGE:
+ g_value_set_string (value, self->priv->requested_message);
+ break;
+ case PROP_NICKNAME:
+ g_value_set_string (value, self->priv->nickname);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
}
}
static void
+_tp_account_dispose (GObject *object)
+{
+ TpAccount *self = TP_ACCOUNT (object);
+ TpAccountPrivate *priv = self->priv;
+
+ if (priv->dispose_has_run)
+ return;
+
+ priv->dispose_has_run = TRUE;
+
+ _tp_account_free_connection (self);
+
+ /* release any references held by the object here */
+ if (G_OBJECT_CLASS (tp_account_parent_class)->dispose != NULL)
+ G_OBJECT_CLASS (tp_account_parent_class)->dispose (object);
+}
+
+static void
+_tp_account_feature_free (gpointer data,
+ gpointer user_data)
+{
+ g_slice_free (TpAccountFeature, data);
+}
+
+static void
+_tp_account_finalize (GObject *object)
+{
+ TpAccount *self = TP_ACCOUNT (object);
+ TpAccountPrivate *priv = self->priv;
+
+ g_free (priv->connection_object_path);
+ g_free (priv->status);
+ g_free (priv->message);
+ g_free (priv->requested_status);
+ g_free (priv->requested_message);
+
+ g_free (priv->nickname);
+
+ g_free (priv->cm_name);
+ g_free (priv->proto_name);
+ g_free (priv->icon_name);
+ g_free (priv->display_name);
+
+ g_list_foreach (priv->features, _tp_account_feature_free, NULL);
+ g_list_free (priv->features);
+ priv->features = NULL;
+
+ /* GSimpleAsyncResult keeps a ref to the source GObject, so this list
+ * should be empty. */
+ g_assert_cmpuint (g_list_length (priv->callbacks), ==, 0);
+
+ g_list_free (priv->callbacks);
+ priv->callbacks = NULL;
+
+ g_array_free (priv->requested_features, TRUE);
+ g_array_free (priv->actual_features, TRUE);
+ g_array_free (priv->missing_features, TRUE);
+
+ /* free any data held directly by the object here */
+ if (G_OBJECT_CLASS (tp_account_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (tp_account_parent_class)->finalize (object);
+}
+
+static void
tp_account_class_init (TpAccountClass *klass)
{
TpProxyClass *proxy_class = (TpProxyClass *) klass;
@@ -137,7 +805,429 @@ tp_account_class_init (TpAccountClass *klass)
g_type_class_add_private (klass, sizeof (TpAccountPrivate));
- object_class->constructed = tp_account_constructed;
+ object_class->constructed = _tp_account_constructed;
+ object_class->get_property = _tp_account_get_property;
+ object_class->dispose = _tp_account_dispose;
+ object_class->finalize = _tp_account_finalize;
+
+ /**
+ * TpAccount:enabled:
+ *
+ * Whether this account is enabled or not.
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * This is not guaranteed to have been retrieved until
+ * tp_account_prepare_async() has finished; until then, the value is FALSE.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_ENABLED,
+ g_param_spec_boolean ("enabled",
+ "Enabled",
+ "Whether this account is enabled or not",
+ FALSE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:current-presence-type:
+ *
+ * The account connection's current presence type.
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * This is not guaranteed to have been retrieved until
+ * tp_account_prepare_async() has finished; until then, the value is
+ * %TP_CONNECTION_PRESENCE_TYPE_UNSET.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_CURRENT_PRESENCE_TYPE,
+ g_param_spec_uint ("current-presence-type",
+ "Presence",
+ "The account connection's current presence type",
+ 0,
+ NUM_TP_CONNECTION_PRESENCE_TYPES,
+ TP_CONNECTION_PRESENCE_TYPE_UNSET,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:current-status:
+ *
+ * The current Status string of the account.
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * This is not guaranteed to have been retrieved until
+ * tp_account_prepare_async() has finished; until then, the value is
+ * %NULL.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_CURRENT_STATUS,
+ g_param_spec_string ("current-status",
+ "Current Status",
+ "The Status string of the account",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount: current-status-message:
+ *
+ * The current status message message of the account.
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * This is not guaranteed to have been retrieved until
+ * tp_account_prepare_async() has finished; until then, the value is
+ * %NULL.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_CURRENT_STATUS_MESSAGE,
+ g_param_spec_string ("current-status-message",
+ "current-status-message",
+ "The Status message string of the account",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:connection-status:
+ *
+ * The account's connection status type.
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * This is not guaranteed to have been retrieved until
+ * tp_account_prepare_async() has finished; until then, the value is
+ * %TP_CONNECTION_STATUS_DISCONNECTED.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_CONNECTION_STATUS,
+ g_param_spec_uint ("connection-status",
+ "ConnectionStatus",
+ "The account's connection status type",
+ 0,
+ NUM_TP_CONNECTION_STATUSES,
+ TP_CONNECTION_STATUS_DISCONNECTED,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:connection-status-reason:
+ *
+ * The account's connection status reason.
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * This is not guaranteed to have been retrieved until
+ * tp_account_prepare_async() has finished; until then, the value is
+ * %TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_CONNECTION_STATUS_REASON,
+ g_param_spec_uint ("connection-status-reason",
+ "ConnectionStatusReason",
+ "The account's connection status reason",
+ 0,
+ NUM_TP_CONNECTION_STATUS_REASONS,
+ TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:connection:
+ *
+ * The connection of the account, or NULL if account is offline.
+ * It is not guaranteed that the returned #TpConnection object is ready.
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * This is not guaranteed to have been retrieved until
+ * tp_account_prepare_async() has finished; until then, the value is
+ * %NULL.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_CONNECTION,
+ g_param_spec_object ("connection",
+ "Connection",
+ "The account's connection",
+ TP_TYPE_CONNECTION,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:display-name:
+ *
+ * The account's display name, from the DisplayName property.
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * This is not guaranteed to have been retrieved until
+ * tp_account_prepare_async() has finished; until then, the value is
+ * %NULL.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_DISPLAY_NAME,
+ g_param_spec_string ("display-name",
+ "DisplayName",
+ "The account's display name",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:connection-manager:
+ *
+ * The account's connection manager name.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_CONNECTION_MANAGER,
+ g_param_spec_string ("connection-manager",
+ "Connection manager",
+ "The account's connection manager name",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:protocol:
+ *
+ * The account's protocol name.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_PROTOCOL,
+ g_param_spec_string ("protocol",
+ "Protocol",
+ "The account's protocol name",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:icon-name:
+ *
+ * The account's icon name. To change this propery, use
+ * tp_account_set_icon_name_async().
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * This is not guaranteed to have been retrieved until
+ * tp_account_prepare_async() has finished; until then, the value is
+ * %NULL.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_ICON_NAME,
+ g_param_spec_string ("icon-name",
+ "Icon",
+ "The account's icon name",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:connect-automatically:
+ *
+ * Whether the account should connect automatically or not. To change this
+ * property, use tp_account_set_connect_automatically_async().
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * This is not guaranteed to have been retrieved until
+ * tp_account_prepare_async() has finished; until then, the value is
+ * %FALSE.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_CONNECT_AUTOMATICALLY,
+ g_param_spec_boolean ("connect-automatically",
+ "ConnectAutomatically",
+ "Whether this account should connect automatically or not",
+ FALSE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:has-been-online:
+ *
+ * Whether this account has been online or not.
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * This is not guaranteed to have been retrieved until
+ * tp_account_prepare_async() has finished; until then, the value is
+ * %FALSE.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_HAS_BEEN_ONLINE,
+ g_param_spec_boolean ("has-been-online",
+ "HasBeenOnline",
+ "Whether this account has been online or not",
+ FALSE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:valid:
+ *
+ * Whether this account is valid.
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * This is not guaranteed to have been retrieved until
+ * tp_account_prepare_async() has finished; until then, the value is
+ * %FALSE.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_VALID,
+ g_param_spec_boolean ("valid",
+ "Valid",
+ "Whether this account is valid",
+ FALSE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:requested-presence-type:
+ *
+ * The account's requested presence type.
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_REQUESTED_PRESENCE_TYPE,
+ g_param_spec_uint ("requested-presence-type",
+ "RequestedPresence",
+ "The account's requested presence type",
+ 0,
+ NUM_TP_CONNECTION_PRESENCE_TYPES,
+ TP_CONNECTION_PRESENCE_TYPE_UNSET,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:requested-status:
+ *
+ * The requested Status string of the account.
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_REQUESTED_STATUS,
+ g_param_spec_string ("requested-status",
+ "RequestedStatus",
+ "The account's requested status string",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:requested-status-message:
+ *
+ * The requested status message message of the account.
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_REQUESTED_STATUS_MESSAGE,
+ g_param_spec_string ("requested-status-message",
+ "RequestedStatusMessage",
+ "The requested Status message string of the account",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount:nickname
+ *
+ * The nickname that should be set for the user on this account.
+ *
+ * One can receive change notifications on this property by connecting
+ * to the #GObject::notify signal and using this property as the signal
+ * detail.
+ *
+ * This is not guaranteed to have been retrieved until
+ * tp_account_prepare_async() has finished; until then, the value is
+ * %NULL.
+ *
+ * Since: 0.9.0
+ */
+ g_object_class_install_property (object_class, PROP_NICKNAME,
+ g_param_spec_string ("nickname",
+ "Nickname",
+ "The account's nickname",
+ NULL,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+ /**
+ * TpAccount::status-changed:
+ * @account: the #TpAccount
+ * @old_status: old connection status
+ * @new_status: new connection status
+ * @reason: the reason for the status change
+ * @dbus_error_name: currently unused, but for exposing the dbus error name
+ * on a connection error in the future
+ * @details: currently unused, but for exposing the error details
+ * on a connection error in the future
+ *
+ * Emitted when the connection status on the account changes.
+ *
+ * Since: 0.9.0
+ */
+ signals[STATUS_CHANGED] = g_signal_new ("status-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ _tp_marshal_VOID__UINT_UINT_UINT_STRING_POINTER,
+ G_TYPE_NONE, 5, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
+ G_TYPE_HASH_TABLE);
+
+ /**
+ * TpAccount::presence-changed:
+ * @account: the #TpAccount
+ * @presence: the new presence
+ * @status: the new presence status
+ * @status_message: the new presence status message
+ *
+ * Emitted when the presence of the account changes.
+ *
+ * Since: 0.9.0
+ */
+ signals[PRESENCE_CHANGED] = g_signal_new ("presence-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ _tp_marshal_VOID__UINT_STRING_STRING,
+ G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
proxy_class->interface = TP_IFACE_QUARK_ACCOUNT;
tp_account_init_known_interfaces ();
@@ -180,7 +1270,8 @@ tp_account_init_known_interfaces (void)
* @object_path: The non-NULL object path of this account
* @error: Used to raise an error if @object_path is not valid
*
- * Convenience function to create a new account proxy.
+ * Convenience function to create a new account proxy. The returned #TpAccount
+ * is not guaranteed to be ready at the point of return.
*
* Returns: a new reference to an account proxy, or %NULL if @object_path is
* not valid
@@ -192,27 +1283,1498 @@ tp_account_new (TpDBusDaemon *bus_daemon,
{
TpAccount *self;
- g_return_val_if_fail (bus_daemon != NULL, NULL);
+ g_return_val_if_fail (TP_IS_DBUS_DAEMON (bus_daemon), NULL);
g_return_val_if_fail (object_path != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- if (!tp_dbus_check_valid_object_path (object_path, error))
+ if (!tp_account_parse_object_path (object_path, NULL, NULL, NULL, error))
+ return NULL;
+
+ self = TP_ACCOUNT (g_object_new (TP_TYPE_ACCOUNT,
+ "dbus-daemon", bus_daemon,
+ "dbus-connection", ((TpProxy *) bus_daemon)->dbus_connection,
+ "bus-name", TP_ACCOUNT_MANAGER_BUS_NAME,
+ "object-path", object_path,
+ NULL));
+
+ return self;
+}
+
+static gchar *
+unescape_protocol (gchar *protocol)
+{
+ if (strstr (protocol, "_2d") != NULL)
+ {
+ /* Work around MC5 bug where it escapes with tp_escape_as_identifier
+ * rather than doing it properly. MC5 saves the object path in your
+ * config, so if you've ever used a buggy MC5, the path will be wrong
+ * forever.
+ */
+ gchar **chunks = g_strsplit (protocol, "_2d", 0);
+ gchar *new = g_strjoinv ("-", chunks);
+
+ g_strfreev (chunks);
+ g_free (protocol);
+ protocol = new;
+ }
+
+ g_strdelimit (protocol, "_", '-');
+
+ return protocol;
+}
+
+/**
+ * tp_account_get_connection:
+ * @account: a #TpAccount
+ *
+ * <!-- -->
+ *
+ * Returns: the same as the #TpAccount:connection property
+ *
+ * Since: 0.9.0
+ **/
+TpConnection *
+tp_account_get_connection (TpAccount *account)
+{
+ TpAccountPrivate *priv;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+
+ priv = account->priv;
+
+ if (priv->connection == NULL && priv->connection_object_path != NULL)
+ _tp_account_set_connection (account, priv->connection_object_path);
+
+ return priv->connection;
+}
+
+/**
+ * tp_account_ensure_connection:
+ * @account: a #TpAccount
+ * @path: the path to connection object for #TpAccount
+ *
+ * Set the connection of the account by specifying the connection object path.
+ * This function does not return a new ref and it is not guaranteed that the
+ * returned #TpConnection object is ready.
+ *
+ * The use-case for this function is in a HandleChannels callback and you
+ * already know the object path for the connection, so you can let @account
+ * create its #TpConnection and return it for use.
+ *
+ * Returns: the connection of the account, or %NULL if either the object path
+ * @path is invalid or it is the null-value "/"
+ *
+ * Since: 0.9.0
+ **/
+TpConnection *
+tp_account_ensure_connection (TpAccount *account,
+ const gchar *path)
+{
+ TpAccountPrivate *priv;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+
+ priv = account->priv;
+
+ /* double-check that the object path is valid */
+ if (!tp_dbus_check_valid_object_path (path, NULL))
+ return NULL;
+
+ /* Should be a full object path, not the special "/" value */
+ if (strlen (path) == 1)
+ return NULL;
+
+ _tp_account_set_connection (account, path);
+
+ return priv->connection;
+}
+
+/**
+ * tp_account_get_display_name:
+ * @account: a #TpAccount
+ *
+ * <!-- -->
+ *
+ * Returns: the same as the #TpAccount:display-name property
+ *
+ * Since: 0.9.0
+ **/
+const gchar *
+tp_account_get_display_name (TpAccount *account)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+
+ return account->priv->display_name;
+}
+
+/**
+ * tp_account_is_valid:
+ * @account: a #TpAccount
+ *
+ * <!-- -->
+ *
+ * Returns: the same as the #TpAccount:valid property
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_is_valid (TpAccount *account)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+
+ return account->priv->valid;
+}
+
+/**
+ * tp_account_get_connection_manager:
+ * @account: a #TpAccount
+ *
+ * <!-- -->
+ *
+ * Returns: the same as the #TpAccount:connection-manager property
+ *
+ * Since: 0.9.0
+ */
+const gchar *
+tp_account_get_connection_manager (TpAccount *account)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+
+ return account->priv->cm_name;
+}
+
+/**
+ * tp_account_get_protocol:
+ * @account: a #TpAccount
+ *
+ * <!-- -->
+ *
+ * Returns: the same as the #TpAccount:protocol property
+ *
+ * Since: 0.9.0
+ */
+const gchar *
+tp_account_get_protocol (TpAccount *account)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+
+ return account->priv->proto_name;
+}
+
+/**
+ * tp_account_get_icon_name:
+ * @account: a #TpAccount
+ *
+ * <!-- -->
+ *
+ * Returns: the same as the #TpAccount:icon-name property
+ *
+ * Since: 0.9.0
+ */
+const gchar *
+tp_account_get_icon_name (TpAccount *account)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+
+ return account->priv->icon_name;
+}
+
+/**
+ * tp_account_get_parameters:
+ * @account: a #TpAccount
+ *
+ * <!-- -->
+ *
+ * Returns: the hash table of parameters on @account
+ *
+ * Since: 0.9.0
+ */
+const GHashTable *
+tp_account_get_parameters (TpAccount *account)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+
+ return account->priv->parameters;
+}
+
+/**
+ * tp_account_is_enabled:
+ * @account: a #TpAccount
+ *
+ * <!-- -->
+ *
+ * Returns: the same as the #TpAccount:enabled property
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_is_enabled (TpAccount *account)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+
+ return account->priv->enabled;
+}
+
+static void
+_tp_account_property_set_cb (TpProxy *proxy,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ GSimpleAsyncResult *result = user_data;
+
+ if (error != NULL)
+ {
+ DEBUG ("Failed to set property: %s", error->message);
+ g_simple_async_result_set_from_error (result, (GError *) error);
+ }
+
+ g_simple_async_result_complete (result);
+ g_object_unref (result);
+}
+
+/**
+ * tp_account_set_enabled_finish:
+ * @account: a #TpAccount
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Finishes an async set of the Enabled property.
+ *
+ * Returns: %TRUE if the set was successful, otherwise %FALSE
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_set_enabled_finish (TpAccount *account,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (account), tp_account_set_enabled_finish), FALSE);
+
+ return TRUE;
+}
+
+/**
+ * tp_account_set_enabled_async:
+ * @account: a #TpAccount
+ * @enabled: the new enabled value of @account
+ * @callback: a callback to call when the request is satisfied
+ * @user_data: data to pass to @callback
+ *
+ * Requests an asynchronous set of the Enabled property of @account. When the
+ * operation is finished, @callback will be called. You can then call
+ * tp_account_set_enabled_finish() to get the result of the operation.
+ *
+ * Since: 0.9.0
+ */
+void
+tp_account_set_enabled_async (TpAccount *account,
+ gboolean enabled,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ TpAccountPrivate *priv;
+ GValue value = {0, };
+ GSimpleAsyncResult *result;
+
+ g_return_if_fail (TP_IS_ACCOUNT (account));
+
+ priv = account->priv;
+
+ result = g_simple_async_result_new (G_OBJECT (account),
+ callback, user_data, tp_account_set_enabled_finish);
+
+ if (priv->enabled == enabled)
+ {
+ g_simple_async_result_complete_in_idle (result);
+ return;
+ }
+
+ g_value_init (&value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (&value, enabled);
+
+ tp_cli_dbus_properties_call_set (TP_PROXY (account),
+ -1, TP_IFACE_ACCOUNT, "Enabled", &value,
+ _tp_account_property_set_cb, result, NULL, G_OBJECT (account));
+
+ g_value_reset (&value);
+}
+
+static void
+_tp_account_reconnected_cb (TpAccount *proxy,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ GSimpleAsyncResult *result = user_data;
+
+ if (error != NULL)
+ g_simple_async_result_set_from_error (result, (GError *) error);
+
+ g_simple_async_result_complete (result);
+ g_object_unref (result);
+}
+
+/**
+ * tp_account_reconnect_finish:
+ * @account: a #TpAccount
+ * @result: a #GAsyncResult
+ * @error: a #GError to be filled
+ *
+ * Finishes an async reconnect of @account.
+ *
+ * Returns: %TRUE if the reconnect call was successful, otherwise %FALSE
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_reconnect_finish (TpAccount *account,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (account), tp_account_reconnect_finish), FALSE);
+
+ return TRUE;
+}
+
+/**
+ * tp_account_reconnect_async:
+ * @account: a #TpAccount
+ * @callback: a callback to call when the request is satisfied
+ * @user_data: data to pass to @callback
+ *
+ * Requests an asynchronous reconnect of @account. When the operation is
+ * finished, @callback will be called. You can then call
+ * tp_account_reconnect_finish() to get the result of the operation.
+ *
+ * Since: 0.9.0
+ */
+void
+tp_account_reconnect_async (TpAccount *account,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ g_return_if_fail (TP_IS_ACCOUNT (account));
+
+ result = g_simple_async_result_new (G_OBJECT (account),
+ callback, user_data, tp_account_reconnect_finish);
+
+ tp_cli_account_call_reconnect (account, -1, _tp_account_reconnected_cb,
+ result, NULL, G_OBJECT (account));
+}
+
+/**
+ * tp_account_request_presence_finish:
+ * @account: a #TpAccount
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Finishes an async presence change request on @account.
+ *
+ * Returns: %TRUE if the operation was successful, otherwise %FALSE
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_request_presence_finish (TpAccount *account,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (account), tp_account_request_presence_finish), FALSE);
+
+ return TRUE;
+}
+
+/**
+ * tp_account_request_presence_async:
+ * @account: a #TpAccount
+ * @type: the requested presence
+ * @status: a status message to set, or %NULL
+ * @message: a message for the change, or %NULL
+ * @callback: a callback to call when the request is satisfied
+ * @user_data: data to pass to @callback
+ *
+ * Requests an asynchronous change of presence on @account. When the
+ * operation is finished, @callback will be called. You can then call
+ * tp_account_request_presence_finish() to get the result of the operation.
+ *
+ * Since: 0.9.0
+ */
+void
+tp_account_request_presence_async (TpAccount *account,
+ TpConnectionPresenceType type,
+ const gchar *status,
+ const gchar *message,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GValue value = {0, };
+ GValueArray *arr;
+ GSimpleAsyncResult *result;
+
+ g_return_if_fail (TP_IS_ACCOUNT (account));
+
+ result = g_simple_async_result_new (G_OBJECT (account),
+ callback, user_data, tp_account_request_presence_finish);
+
+ g_value_init (&value, TP_STRUCT_TYPE_SIMPLE_PRESENCE);
+ g_value_take_boxed (&value, dbus_g_type_specialized_construct (
+ TP_STRUCT_TYPE_SIMPLE_PRESENCE));
+ arr = (GValueArray *) g_value_get_boxed (&value);
+
+ g_value_set_uint (arr->values, type);
+ g_value_set_static_string (arr->values + 1, status);
+ g_value_set_static_string (arr->values + 2, message);
+
+ tp_cli_dbus_properties_call_set (TP_PROXY (account), -1,
+ TP_IFACE_ACCOUNT, "RequestedPresence", &value,
+ _tp_account_property_set_cb, result, NULL, G_OBJECT (account));
+
+ g_value_unset (&value);
+}
+
+static void
+_tp_account_updated_cb (TpAccount *proxy,
+ const gchar **reconnect_required,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ if (error != NULL)
+ g_simple_async_result_set_from_error (result, (GError *) error);
+ else
+ g_simple_async_result_set_op_res_gpointer (result, reconnect_required, NULL);
+
+ g_simple_async_result_complete (result);
+ g_object_unref (G_OBJECT (result));
+}
+
+/**
+ * tp_account_update_parameters_async:
+ * @account: a #TpAccount
+ * @parameters: new parameters to set on @account
+ * @unset_parameters: list of parameters to unset on @account
+ * @callback: a callback to call when the request is satisfied
+ * @user_data: data to pass to @callback
+ *
+ * Requests an asynchronous update of parameters of @account. When the
+ * operation is finished, @callback will be called. You can then call
+ * tp_account_update_parameters_finish() to get the result of the operation.
+ *
+ * Since: 0.9.0
+ */
+void
+tp_account_update_parameters_async (TpAccount *account,
+ GHashTable *parameters,
+ const gchar **unset_parameters,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ g_return_if_fail (TP_IS_ACCOUNT (account));
+
+ result = g_simple_async_result_new (G_OBJECT (account),
+ callback, user_data, tp_account_update_parameters_finish);
+
+ tp_cli_account_call_update_parameters (account, -1, parameters,
+ unset_parameters, _tp_account_updated_cb, result,
+ NULL, G_OBJECT (account));
+}
+
+/**
+ * tp_account_update_parameters_finish:
+ * @account: a #TpAccount
+ * @result: a #GAsyncResult
+ * @reconnect_required: a #GStrv to fill with properties that need a reconnect
+ * to take effect
+ * @error: a #GError to fill
+ *
+ * Finishes an async update of the parameters on @account.
+ *
+ * Returns: %TRUE if the request succeeded, otherwise %FALSE
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_update_parameters_finish (TpAccount *account,
+ GAsyncResult *result,
+ gchar ***reconnect_required,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (account), tp_account_update_parameters_finish), FALSE);
+
+ if (reconnect_required != NULL)
+ *reconnect_required =
+ g_strdupv (g_simple_async_result_get_op_res_gpointer (simple));
+
+ return TRUE;
+}
+
+/**
+ * tp_account_set_display_name_async:
+ * @account: a #TpAccount
+ * @display_name: a new display name, or %NULL to unset the display name
+ * @callback: a callback to call when the request is satisfied
+ * @user_data: data to pass to @callback
+ *
+ * Requests an asynchronous set of the DisplayName property of @account. When
+ * the operation is finished, @callback will be called. You can then call
+ * tp_account_set_display_name_finish() to get the result of the operation.
+ *
+ * Since: 0.9.0
+ */
+void
+tp_account_set_display_name_async (TpAccount *account,
+ const char *display_name,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+ GValue value = {0, };
+ const gchar *display_name_set;
+
+ g_return_if_fail (TP_IS_ACCOUNT (account));
+
+ if (display_name == NULL)
+ display_name_set = "";
+ else
+ display_name_set = display_name;
+
+ result = g_simple_async_result_new (G_OBJECT (account), callback,
+ user_data, tp_account_set_display_name_finish);
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, display_name_set);
+
+ tp_cli_dbus_properties_call_set (account, -1, TP_IFACE_ACCOUNT,
+ "DisplayName", &value, _tp_account_property_set_cb, result, NULL,
+ G_OBJECT (account));
+
+ g_value_unset (&value);
+}
+
+/**
+ * tp_account_set_display_name_finish:
+ * @account: a #TpAccount
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Finishes an async set of the DisplayName property.
+ *
+ * Returns: %TRUE if the call was successful, otherwise %FALSE
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_set_display_name_finish (TpAccount *account,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (account), tp_account_set_display_name_finish), FALSE);
+
+ return TRUE;
+}
+
+/**
+ * tp_account_set_icon_name_async:
+ * @account: a #TpAccount
+ * @icon_name: a new icon name, or %NULL to unset the icon name
+ * @callback: a callback to call when the request is satisfied
+ * @user_data: data to pass to @callback
+ *
+ * Requests an asynchronous set of the Icon property of @account. When
+ * the operation is finished, @callback will be called. You can then call
+ * tp_account_set_icon_name_finish() to get the result of the operation.
+ *
+ * Since: 0.9.0
+ */
+void
+tp_account_set_icon_name_async (TpAccount *account,
+ const char *icon_name,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+ GValue value = {0, };
+ const char *icon_name_set;
+
+ g_return_if_fail (TP_IS_ACCOUNT (account));
+
+ if (icon_name == NULL)
+ /* settings an empty icon name is allowed */
+ icon_name_set = "";
+ else
+ icon_name_set = icon_name;
+
+ result = g_simple_async_result_new (G_OBJECT (account), callback,
+ user_data, tp_account_set_icon_name_finish);
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, icon_name_set);
+
+ tp_cli_dbus_properties_call_set (account, -1, TP_IFACE_ACCOUNT,
+ "Icon", &value, _tp_account_property_set_cb, result, NULL,
+ G_OBJECT (account));
+
+ g_value_unset (&value);
+}
+
+/**
+ * tp_account_set_icon_name_finish:
+ * @account: a #TpAccount
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Finishes an async set of the Icon parameter.
+ *
+ * Returns: %TRUE if the operation was successful, otherwise %FALSE
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_set_icon_name_finish (TpAccount *account,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (account), tp_account_set_icon_name_finish), FALSE);
+
+ return TRUE;
+}
+
+static void
+_tp_account_remove_cb (TpAccount *proxy,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ if (error != NULL)
+ g_simple_async_result_set_from_error (result, (GError *) error);
+
+ g_simple_async_result_complete (result);
+ g_object_unref (G_OBJECT (result));
+}
+
+/**
+ * tp_account_remove_async:
+ * @account: a #TpAccount
+ * @callback: a callback to call when the request is satisfied
+ * @user_data: data to pass to @callback
+ *
+ * Requests an asynchronous removal of @account. When the operation is
+ * finished, @callback will be called. You can then call
+ * tp_account_remove_finish() to get the result of the operation.
+ *
+ * Since: 0.9.0
+ */
+void
+tp_account_remove_async (TpAccount *account,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ g_return_if_fail (TP_IS_ACCOUNT (account));
+
+ result = g_simple_async_result_new (G_OBJECT (account),
+ callback, user_data, tp_account_remove_finish);
+
+ tp_cli_account_call_remove (account, -1, _tp_account_remove_cb, result, NULL,
+ G_OBJECT (account));
+}
+
+/**
+ * tp_account_remove_finish:
+ * @account: a #TpAccount
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Finishes an async removal of @account.
+ *
+ * Returns: %TRUE if the operation was successful, otherwise %FALSE
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_remove_finish (TpAccount *account,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (account), tp_account_remove_finish), FALSE);
+
+ return TRUE;
+}
+
+/**
+ * tp_account_get_connect_automatically:
+ * @account: a #TpAccount
+ *
+ * <!-- -->
+ *
+ * Returns: the same as the #TpAccount:connect-automatically property
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_get_connect_automatically (TpAccount *account)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+
+ return account->priv->connect_automatically;
+}
+
+/**
+ * tp_account_set_connect_automatically_async:
+ * @account: a #TpAccount
+ * @connect_automatically: new value for the parameter
+ * @callback: a callback to call when the request is satisfied
+ * @user_data: data to pass to @callback
+ *
+ * Requests an asynchronous set of the ConnectAutomatically property of
+ * @account. When the operation is finished, @callback will be called. You can
+ * then call tp_account_set_display_name_finish() to get the result of the
+ * operation.
+ *
+ * Since: 0.9.0
+ */
+void
+tp_account_set_connect_automatically_async (TpAccount *account,
+ gboolean connect_automatically,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+ GValue value = {0, };
+
+ g_return_if_fail (TP_IS_ACCOUNT (account));
+
+ result = g_simple_async_result_new (G_OBJECT (account), callback,
+ user_data, tp_account_set_connect_automatically_finish);
+
+ g_value_init (&value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (&value, connect_automatically);
+
+ tp_cli_dbus_properties_call_set (account, -1, TP_IFACE_ACCOUNT,
+ "ConnectAutomatically", &value, _tp_account_property_set_cb, result,
+ NULL, G_OBJECT (account));
+
+ g_value_unset (&value);
+}
+
+/**
+ * tp_account_set_connect_automatically_finish:
+ * @account: a #TpAccount
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Finishes an async set of the ConnectAutomatically property.
+ *
+ * Returns: %TRUE if the call was successful, otherwise %FALSE
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_set_connect_automatically_finish (TpAccount *account,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (account), tp_account_set_connect_automatically_finish), FALSE);
+
+ return TRUE;
+}
+
+/**
+ * tp_account_get_has_been_online:
+ * @account: a #TpAccount
+ *
+ * <!-- -->
+ *
+ * Returns: the same as the #TpAccount:has-been-online property
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_get_has_been_online (TpAccount *account)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+
+ return account->priv->has_been_online;
+}
+
+/**
+ * tp_account_get_connection_status:
+ * @account: a #TpAccount
+ * @reason: a #TpConnectionStatusReason to fill, or %NULL
+ *
+ * Gets the connection status and reason from @account. The two values
+ * are the same as the #TpAccount:connection-status and
+ * #TpAccount:connection-status-reason properties.
+ *
+ * Returns: the same as the #TpAccount:connection-status property
+ *
+ * Since: 0.9.0
+ */
+TpConnectionStatus
+tp_account_get_connection_status (TpAccount *account,
+ TpConnectionStatusReason *reason)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account),
+ TP_CONNECTION_STATUS_DISCONNECTED); /* there's no _UNSET */
+
+ if (reason != NULL)
+ *reason = account->priv->reason;
+
+ return account->priv->connection_status;
+}
+
+/**
+ * tp_account_get_current_presence:
+ * @account: a #TpAccount
+ * @status: return location for the current status
+ * @status_message: return location for the current status message
+ *
+ * Gets the current presence, status and status message of @account. These
+ * values are the same as the #TpAccount:current-presence-type,
+ * #TpAccount:current-status and #TpAccount:current-status-message properties.
+ *
+ * Returns: the same as the #TpAccount:current-presence-type property
+ *
+ * Since: 0.9.0
+ */
+TpConnectionPresenceType
+tp_account_get_current_presence (TpAccount *account,
+ gchar **status,
+ gchar **status_message)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account),
+ TP_CONNECTION_PRESENCE_TYPE_UNSET);
+
+ if (status != NULL)
+ *status = g_strdup (account->priv->status);
+
+ if (status_message != NULL)
+ *status_message = g_strdup (account->priv->message);
+
+ return account->priv->presence;
+}
+
+/**
+ * tp_account_get_requested_presence:
+ * @account: a #TpAccount
+ * @status: return location for the requested status
+ * @status_message: return location for the requested status message
+ *
+ * Gets the requested presence, status and status message of @account. These
+ * values are the same as the #TpAccount:requested-presence-type,
+ * #TpAccount:requested-status and #TpAccount:requested-status-message
+ * properties.
+ *
+ * Returns: the same as the #TpAccount:requested-presence-type property
+ *
+ * Since: 0.9.0
+ */
+TpConnectionPresenceType
+tp_account_get_requested_presence (TpAccount *account,
+ gchar **status,
+ gchar **status_message)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account),
+ TP_CONNECTION_PRESENCE_TYPE_UNSET);
+
+ if (status != NULL)
+ *status = g_strdup (account->priv->requested_status);
+
+ if (status_message != NULL)
+ *status_message = g_strdup (account->priv->requested_message);
+
+ return account->priv->requested_presence;
+}
+
+/**
+ * tp_account_get_nickname:
+ * @account: a #TpAccount
+ *
+ * <!-- -->
+ *
+ * Returns: the same as the #TpAccount:nickname property
+ *
+ * Since: 0.9.0
+ */
+const gchar *
+tp_account_get_nickname (TpAccount *account)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+
+ return account->priv->nickname;
+}
+
+/**
+ * tp_account_set_nickname_finish:
+ * @account: a #TpAccount
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Finishes an async nickname change request on @account.
+ *
+ * Returns: %TRUE if the operation was successful, otherwise %FALSE
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_set_nickname_finish (TpAccount *account,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (account), tp_account_set_nickname_finish), FALSE);
+
+ return TRUE;
+}
+
+/**
+ * tp_account_set_nickname_async:
+ * @account: a #TpAccount
+ * @nickname: a new nickname to set
+ * @callback: a callback to call when the request is satisfied
+ * @user_data: data to pass to @callback
+ *
+ * Requests an asynchronous change of the Nickname parameter on @account. When
+ * the operation is finished, @callback will be called. You can then call
+ * tp_account_set_nickname_finish() to get the result of the operation.
+ *
+ * Since: 0.9.0
+ */
+void
+tp_account_set_nickname_async (TpAccount *account,
+ const gchar *nickname,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GValue value = {0, };
+ GSimpleAsyncResult *result;
+
+ g_return_if_fail (TP_IS_ACCOUNT (account));
+ g_return_if_fail (nickname != NULL);
+
+ result = g_simple_async_result_new (G_OBJECT (account),
+ callback, user_data, tp_account_request_presence_finish);
+
+ if (nickname == NULL)
+ {
+ g_simple_async_report_error_in_idle (G_OBJECT (account),
+ callback, user_data, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ "Can't set an empty nickname");
+ return;
+ }
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, nickname);
+
+ tp_cli_dbus_properties_call_set (TP_PROXY (account), -1,
+ TP_IFACE_ACCOUNT, "Nickname", &value,
+ _tp_account_property_set_cb, result, NULL, G_OBJECT (account));
+
+ g_value_unset (&value);
+}
+
+static void
+_tp_account_got_avatar_cb (TpProxy *proxy,
+ const GValue *out_Value,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data);
+ GValueArray *avatar;
+ GArray *res;
+
+ if (error != NULL)
+ {
+ DEBUG ("Failed to get avatar: %s", error->message);
+ g_simple_async_result_set_from_error (result, (GError *) error);
+ }
+ else
+ {
+ avatar = g_value_get_boxed (out_Value);
+ res = g_value_get_boxed (g_value_array_get_nth (avatar, 0));
+ g_simple_async_result_set_op_res_gpointer (result, res, NULL);
+ }
+
+ g_simple_async_result_complete (result);
+ g_object_unref (result);
+}
+
+/**
+ * tp_account_get_avatar_async:
+ * @account: a #TpAccount
+ * @callback: a callback to call when the request is satisfied
+ * @user_data: data to pass to @callback
+ *
+ * Requests an asynchronous get of @account's avatar. When
+ * the operation is finished, @callback will be called. You can then call
+ * tp_account_get_avatar_finish() to get the result of the operation.
+ *
+ * Since: 0.9.0
+ */
+void
+tp_account_get_avatar_async (TpAccount *account,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ g_return_if_fail (TP_IS_ACCOUNT (account));
+
+ result = g_simple_async_result_new (G_OBJECT (account),
+ callback, user_data, tp_account_get_avatar_finish);
+
+ tp_cli_dbus_properties_call_get (account, -1,
+ TP_IFACE_ACCOUNT_INTERFACE_AVATAR, "Avatar", _tp_account_got_avatar_cb,
+ result, NULL, G_OBJECT (account));
+}
+
+/**
+ * tp_account_get_avatar_finish:
+ * @account: a #TpAccount
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Finishes an async get operation of @account's avatar.
+ *
+ * Returns: a #GArray of the account's avatar, or %NULL on failure
+ *
+ * Since: 0.9.0
+ */
+const GArray *
+tp_account_get_avatar_finish (TpAccount *account,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
return NULL;
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (account), tp_account_get_avatar_finish), NULL);
+
+ return g_simple_async_result_get_op_res_gpointer (
+ G_SIMPLE_ASYNC_RESULT (result));
+}
+
+/**
+ * tp_account_is_prepared:
+ * @account: a #TpAccount
+ * @feature: a feature which is required
+ *
+ * <!-- -->
+ *
+ * Returns: %TRUE whether @feature is ready on @account, otherwise %FALSE
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_is_prepared (TpAccount *account,
+ GQuark feature)
+{
+ TpAccountFeature *f;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+
+ if (tp_proxy_get_invalidated (account) != NULL)
+ return FALSE;
+
+ f = _tp_account_get_feature (account, feature);
+
+ if (f == NULL)
+ return FALSE;
+
+ return f->ready;
+}
+
+/**
+ * tp_account_prepare_async:
+ * @account: a #TpAccount
+ * @features: a 0-terminated list of features, or %NULL
+ * @callback: a callback to call when the request is satisfied
+ * @user_data: data to pass to @callback
+ *
+ * Requests an asynchronous preparation of @account with the features specified
+ * by @features. When the operation is finished, @callback will be called. You
+ * can then call tp_account_prepare_finish() to get the result of the
+ * operation.
+ *
+ * If @features is %NULL, then @callback will be called when the implied
+ * %TP_ACCOUNT_FEATURE_CORE feature is ready.
+ *
+ * If %NULL is given to @callback, then no callback will be called when the
+ * operation is finished. Instead, it will simply set @features on @manager.
+ * Note that if @callback is %NULL, then @user_data must also be %NULL.
+ *
+ * Since: 0.9.0
+ */
+void
+tp_account_prepare_async (TpAccount *account,
+ const GQuark *features,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ TpAccountPrivate *priv;
+ GSimpleAsyncResult *result;
+ const GQuark *f;
+
+ g_return_if_fail (TP_IS_ACCOUNT (account));
+
+ priv = account->priv;
+
+ /* In this object, there are no features which are activatable (core is
+ * forced on you). They'd be activated here though. */
+
+ for (f = features; f != NULL && *f != 0; f++)
+ {
+ /* Only add features to requested which exist on this object and are not
+ * already in the list. */
+ if (_tp_account_get_feature (account, *f) != NULL
+ && _tp_account_feature_in_array (*f, priv->requested_features))
+ g_array_append_val (priv->requested_features, *f);
+ }
+
+ if (callback == NULL)
+ return;
+
+ result = g_simple_async_result_new (G_OBJECT (account),
+ callback, user_data, tp_account_prepare_finish);
+
+ if (_tp_account_check_features (account, features))
+ {
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+ }
+ else
+ {
+ TpAccountFeatureCallback *cb;
+
+ cb = g_slice_new0 (TpAccountFeatureCallback);
+ cb->result = result;
+ cb->features = features;
+ priv->callbacks = g_list_prepend (priv->callbacks, cb);
+ }
+}
+
+/**
+ * tp_account_prepare_finish:
+ * @account: a #TpAccount
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Finishes an async preparation of the account @account.
+ *
+ * Returns: %TRUE if the preparation was successful, otherwise %FALSE
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_prepare_finish (TpAccount *account,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (account), tp_account_prepare_finish), FALSE);
+
+ return TRUE;
+}
+
+/**
+ * _tp_account_get_requested_features:
+ * @account: a #TpAccount
+ *
+ * <!-- -->
+ *
+ * Returns: a 0-terminated list of features requested on @account
+ *
+ * Since: 0.9.0
+ */
+const GQuark *
+_tp_account_get_requested_features (TpAccount *account)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+
+ return (const GQuark *) account->priv->requested_features->data;
+}
+
+/**
+ * _tp_account_get_actual_features:
+ * @account: a #TpAccount
+ *
+ * <!-- -->
+ *
+ * Returns: a 0-terminated list of actual features on @account
+ *
+ * Since: 0.9.0
+ */
+const GQuark *
+_tp_account_get_actual_features (TpAccount *account)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+
+ return (const GQuark *) account->priv->actual_features->data;
+}
+
+/**
+ * _tp_account_get_missing_features:
+ * @account: a #TpAccount
+ *
+ * <!-- -->
+ *
+ * Returns: a 0-terminated list of missing features from @account
+ * that have been requested
+ *
+ * Since: 0.9.0
+ */
+const GQuark *
+_tp_account_get_missing_features (TpAccount *account)
+{
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+
+ return (const GQuark *) account->priv->missing_features->data;
+}
+
+static void
+set_or_free (gchar **target,
+ gchar *source)
+{
+ if (target != NULL)
+ *target = source;
+ else
+ g_free (source);
+}
+
+/**
+ * tp_account_parse_object_path:
+ * @object_path: a Telepathy Account's object path
+ * @cm: location at which to store the account's connection manager's name
+ * @protocol: location at which to store the account's protocol
+ * @account_id: location at which to store the account's unique identifier
+ * @error: location at which to return an error
+ *
+ * Validates and parses a Telepathy Account's object path, extracting the
+ * connection manager's name, the protocol, and the account's unique identifier
+ * from the path. This includes replacing underscores with hyphens in the
+ * protocol name, as defined in the Account specification.
+ *
+ * Any of the out parameters may be %NULL if not needed.
+ *
+ * Returns: %TRUE if @object_path was successfully parsed; %FALSE and sets
+ * @error otherwise.
+ *
+ * Since: 0.9.0
+ */
+gboolean
+tp_account_parse_object_path (const gchar *object_path,
+ gchar **cm,
+ gchar **protocol,
+ gchar **account_id,
+ GError **error)
+{
+ const gchar *suffix;
+ gchar **segments;
+
+ if (!tp_dbus_check_valid_object_path (object_path, error))
+ return FALSE;
+
if (!g_str_has_prefix (object_path, TP_ACCOUNT_OBJECT_PATH_BASE))
{
g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
"Account path does not start with the right prefix: %s",
object_path);
- return NULL;
+ return FALSE;
}
- self = TP_ACCOUNT (g_object_new (TP_TYPE_ACCOUNT,
- "dbus-daemon", bus_daemon,
- "dbus-connection", ((TpProxy *) bus_daemon)->dbus_connection,
- "bus-name", TP_ACCOUNT_MANAGER_BUS_NAME,
- "object-path", object_path,
- NULL));
+ suffix = object_path + strlen (TP_ACCOUNT_OBJECT_PATH_BASE);
- return self;
+ segments = g_strsplit (suffix, "/", 0);
+
+ if (g_strv_length (segments) != 3)
+ {
+ g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+ "Account path '%s' is malformed: should have 3 trailing components, "
+ "not %u", object_path, g_strv_length (segments));
+ goto free_segments_and_fail;
+ }
+
+ if (!g_ascii_isalpha (segments[0][0]))
+ {
+ g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+ "Account path '%s' is malformed: CM name should start with a letter",
+ object_path);
+ goto free_segments_and_fail;
+ }
+
+ if (!g_ascii_isalpha (segments[1][0]))
+ {
+ g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+ "Account path '%s' is malformed: "
+ "protocol name should start with a letter",
+ object_path);
+ goto free_segments_and_fail;
+ }
+
+ if (!g_ascii_isalpha (segments[2][0]) && segments[2][0] != '_')
+ {
+ g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+ "Account path '%s' is malformed: "
+ "account ID should start with a letter or underscore",
+ object_path);
+ goto free_segments_and_fail;
+ }
+
+ set_or_free (cm, segments[0]);
+ set_or_free (protocol, unescape_protocol (segments[1]));
+ set_or_free (account_id, segments[2]);
+
+ /* Not g_strfreev because we stole or freed the individual strings */
+ g_free (segments);
+ return TRUE;
+
+free_segments_and_fail:
+ g_strfreev (segments);
+ return FALSE;
+}
+
+/**
+ * _tp_account_refresh_properties:
+ * @account: a #TpAccount
+ *
+ * Refreshes @account's hashtable of properties with what actually exists on
+ * the account manager.
+ *
+ * Since: 0.9.0
+ */
+void
+_tp_account_refresh_properties (TpAccount *account)
+{
+ g_return_if_fail (TP_IS_ACCOUNT (account));
+
+ tp_cli_dbus_properties_call_get_all (account, -1, TP_IFACE_ACCOUNT,
+ _tp_account_got_all_cb, NULL, NULL, G_OBJECT (account));
}
diff --git a/telepathy-glib/account.h b/telepathy-glib/account.h
index 4072d7509..b9d9feb25 100644
--- a/telepathy-glib/account.h
+++ b/telepathy-glib/account.h
@@ -22,6 +22,9 @@
#ifndef TP_ACCOUNT_H
#define TP_ACCOUNT_H
+#include <gio/gio.h>
+
+#include <telepathy-glib/connection.h>
#include <telepathy-glib/proxy.h>
#include <telepathy-glib/dbus.h>
@@ -63,11 +66,126 @@ GType tp_account_get_type (void);
(G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TYPE_ACCOUNT, \
TpAccountClass))
+#define TP_ACCOUNT_FEATURE_CORE \
+ tp_account_get_feature_quark_core ()
+
+GQuark tp_account_get_feature_quark_core (void) G_GNUC_CONST;
+
TpAccount *tp_account_new (TpDBusDaemon *bus_daemon, const gchar *object_path,
GError **error);
+gboolean tp_account_parse_object_path (const gchar *object_path,
+ gchar **cm, gchar **protocol, gchar **account_id, GError **error);
+
void tp_account_init_known_interfaces (void);
+TpConnection *tp_account_get_connection (TpAccount *account);
+
+TpConnection *tp_account_ensure_connection (TpAccount *account,
+ const gchar *path);
+
+const gchar *tp_account_get_display_name (TpAccount *account);
+
+const gchar *tp_account_get_connection_manager (TpAccount *account);
+
+const gchar *tp_account_get_protocol (TpAccount *account);
+
+const gchar *tp_account_get_icon_name (TpAccount *account);
+
+void tp_account_set_enabled_async (TpAccount *account,
+ gboolean enabled, GAsyncReadyCallback callback, gpointer user_data);
+
+gboolean tp_account_set_enabled_finish (TpAccount *account,
+ GAsyncResult *result, GError **error);
+
+void tp_account_reconnect_async (TpAccount *account,
+ GAsyncReadyCallback callback, gpointer user_data);
+
+gboolean tp_account_reconnect_finish (TpAccount *account,
+ GAsyncResult *result, GError **error);
+
+gboolean tp_account_is_enabled (TpAccount *account);
+
+gboolean tp_account_is_valid (TpAccount *account);
+
+void tp_account_update_parameters_async (TpAccount *account,
+ GHashTable *parameters, const gchar **unset_parameters,
+ GAsyncReadyCallback callback, gpointer user_data);
+
+gboolean tp_account_update_parameters_finish (TpAccount *account,
+ GAsyncResult *result, gchar ***reconnect_required, GError **error);
+
+void tp_account_remove_async (TpAccount *account,
+ GAsyncReadyCallback callback, gpointer user_data);
+
+gboolean tp_account_remove_finish (TpAccount *account,
+ GAsyncResult *result, GError **error);
+
+void tp_account_set_display_name_async (TpAccount *account,
+ const gchar *display_name, GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean tp_account_set_display_name_finish (TpAccount *account,
+ GAsyncResult *result, GError **error);
+
+void tp_account_set_icon_name_async (TpAccount *account,
+ const gchar *icon_name, GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean tp_account_set_icon_name_finish (TpAccount *account,
+ GAsyncResult *result, GError **error);
+
+void tp_account_request_presence_async (TpAccount *account,
+ TpConnectionPresenceType type, const gchar *status, const gchar *message,
+ GAsyncReadyCallback callback, gpointer user_data);
+
+gboolean tp_account_request_presence_finish (TpAccount *account,
+ GAsyncResult *result, GError **error);
+
+gboolean tp_account_get_connect_automatically (TpAccount *account);
+
+void tp_account_set_connect_automatically_async (TpAccount *account,
+ gboolean connect_automatically, GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean tp_account_set_connect_automatically_finish (TpAccount *account,
+ GAsyncResult *result, GError **error);
+
+gboolean tp_account_get_has_been_online (TpAccount *account);
+
+TpConnectionStatus tp_account_get_connection_status (TpAccount *account,
+ TpConnectionStatusReason *reason);
+
+TpConnectionPresenceType tp_account_get_current_presence (TpAccount *account,
+ gchar **status, gchar **status_message);
+
+TpConnectionPresenceType tp_account_get_requested_presence (
+ TpAccount *account, gchar **status, gchar **status_message);
+
+const GHashTable *tp_account_get_parameters (TpAccount *account);
+
+const gchar *tp_account_get_nickname (TpAccount *account);
+
+void tp_account_set_nickname_async (TpAccount *account,
+ const gchar *nickname, GAsyncReadyCallback callback, gpointer user_data);
+
+gboolean tp_account_set_nickname_finish (TpAccount *account,
+ GAsyncResult *result, GError **error);
+
+void tp_account_get_avatar_async (TpAccount *account,
+ GAsyncReadyCallback callback, gpointer user_data);
+
+const GArray *tp_account_get_avatar_finish (TpAccount *account,
+ GAsyncResult *result, GError **error);
+
+gboolean tp_account_is_prepared (TpAccount *account, GQuark feature);
+
+void tp_account_prepare_async (TpAccount *account, const GQuark *features,
+ GAsyncReadyCallback callback, gpointer user_data);
+
+gboolean tp_account_prepare_finish (TpAccount *account, GAsyncResult *result,
+ GError **error);
+
G_END_DECLS
#include <telepathy-glib/_gen/tp-cli-account.h>
diff --git a/telepathy-glib/signals-marshal.list b/telepathy-glib/signals-marshal.list
index 0d7a7eede..b157c9ae7 100644
--- a/telepathy-glib/signals-marshal.list
+++ b/telepathy-glib/signals-marshal.list
@@ -1,3 +1,4 @@
+VOID:OBJECT,INT,UINT,UINT
VOID:OBJECT,POINTER
VOID:OBJECT,POINTER,POINTER
VOID:POINTER,OBJECT
@@ -5,3 +6,6 @@ VOID:POINTER,UINT,INT,STRING
VOID:STRING,UINT,UINT,BOXED
VOID:UINT,INT,STRING
VOID:UINT,OBJECT
+VOID:UINT,STRING,STRING
+VOID:UINT,UINT,UINT,STRING,POINTER
+VOID:OBJECT,BOOLEAN
diff --git a/telepathy-glib/telepathy-glib-uninstalled.pc.in b/telepathy-glib/telepathy-glib-uninstalled.pc.in
index 7adc8c4c4..6d62d0ee7 100644
--- a/telepathy-glib/telepathy-glib-uninstalled.pc.in
+++ b/telepathy-glib/telepathy-glib-uninstalled.pc.in
@@ -7,6 +7,6 @@ Name: Telepathy-GLib (uninstalled copy)
Description: GLib utility library for the Telepathy framework
Version: @VERSION@
Requires: pkg-config >= 0.21
-Requires.private: dbus-glib-1 >= 0.73, glib-2.0 >= 2.16, gobject-2.0 >= 2.16
+Requires.private: dbus-glib-1 >= 0.73, glib-2.0 >= 2.20, gobject-2.0 >= 2.20, gio-2.0 >= 2.20
Libs: ${abs_top_builddir}/telepathy-glib/libtelepathy-glib.la
Cflags: -I${abs_top_srcdir} -I${abs_top_builddir}
diff --git a/telepathy-glib/telepathy-glib.pc.in b/telepathy-glib/telepathy-glib.pc.in
index 8560f0366..b52f0c48f 100644
--- a/telepathy-glib/telepathy-glib.pc.in
+++ b/telepathy-glib/telepathy-glib.pc.in
@@ -7,6 +7,6 @@ Name: Telepathy-GLib
Description: GLib utility library for the Telepathy framework
Version: @VERSION@
Requires: pkg-config >= 0.21
-Requires.private: dbus-glib-1 >= 0.73, glib-2.0 >= 2.16, gobject-2.0 >= 2.16
+Requires.private: dbus-glib-1 >= 0.73, glib-2.0 >= 2.20, gobject-2.0 >= 2.20, gio-2.0 >= 2.20
Libs: -L${libdir} -ltelepathy-glib
Cflags: -I${includedir}/telepathy-1.0
diff --git a/telepathy-glib/versions/0.9.0.abi b/telepathy-glib/versions/0.9.0.abi
new file mode 100644
index 000000000..2be1ed781
--- /dev/null
+++ b/telepathy-glib/versions/0.9.0.abi
@@ -0,0 +1,56 @@
+Version: TELEPATHY_GLIB_0.9.0
+Extends: TELEPATHY_GLIB_0.7.37
+Release: 0.9.0
+
+tp_account_ensure_connection
+tp_account_get_avatar_async
+tp_account_get_avatar_finish
+tp_account_get_connect_automatically
+tp_account_get_connection
+tp_account_get_connection_manager
+tp_account_get_connection_status
+tp_account_get_current_presence
+tp_account_get_display_name
+tp_account_get_feature_quark_core
+tp_account_get_has_been_online
+tp_account_get_icon_name
+tp_account_get_nickname
+tp_account_get_parameters
+tp_account_get_protocol
+tp_account_get_requested_presence
+tp_account_is_enabled
+tp_account_is_prepared
+tp_account_is_valid
+tp_account_manager_create_account_async
+tp_account_manager_create_account_finish
+tp_account_manager_dup
+tp_account_manager_enable_restart
+tp_account_manager_ensure_account
+tp_account_manager_get_feature_quark_core
+tp_account_manager_get_most_available_presence
+tp_account_manager_get_valid_accounts
+tp_account_manager_is_prepared
+tp_account_manager_prepare_async
+tp_account_manager_prepare_finish
+tp_account_manager_set_all_requested_presences
+tp_account_parse_object_path
+tp_account_prepare_async
+tp_account_prepare_finish
+tp_account_reconnect_async
+tp_account_reconnect_finish
+tp_account_remove_async
+tp_account_remove_finish
+tp_account_request_presence_async
+tp_account_request_presence_finish
+tp_account_set_connect_automatically_async
+tp_account_set_connect_automatically_finish
+tp_account_set_display_name_async
+tp_account_set_display_name_finish
+tp_account_set_enabled_async
+tp_account_set_enabled_finish
+tp_account_set_icon_name_async
+tp_account_set_icon_name_finish
+tp_account_set_nickname_async
+tp_account_set_nickname_finish
+tp_account_update_parameters_async
+tp_account_update_parameters_finish
diff --git a/tests/Makefile.am b/tests/Makefile.am
index cb672df16..b9159abea 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -73,7 +73,8 @@ include $(top_srcdir)/tools/check-coding-style.mk
check-local: check-coding-style
LDADD = \
- $(top_builddir)/telepathy-glib/libtelepathy-glib.la
+ $(top_builddir)/telepathy-glib/libtelepathy-glib.la \
+ $(GLIB_LIBS)
AM_CFLAGS = \
$(ERROR_CFLAGS) \
diff --git a/tests/dbus/Makefile.am b/tests/dbus/Makefile.am
index 9be880e8e..142c14927 100644
--- a/tests/dbus/Makefile.am
+++ b/tests/dbus/Makefile.am
@@ -1,5 +1,3 @@
-include $(top_srcdir)/tools/shave.mk
-
noinst_PROGRAMS = \
test-account \
test-account-manager \
@@ -45,7 +43,8 @@ TESTS = $(noinst_PROGRAMS)
LDADD = \
$(top_builddir)/telepathy-glib/libtelepathy-glib.la \
- $(top_builddir)/tests/lib/libtp-glib-tests.la
+ $(top_builddir)/tests/lib/libtp-glib-tests.la \
+ $(GLIB_LIBS)
test_account_SOURCES = account.c
@@ -207,7 +206,7 @@ _gen/svc.c _gen/svc.h: with-properties.xml \
$(top_srcdir)/tools/glib-ginterface-gen.py \
Makefile.am
$(mkdir_p) _gen
- $(QUIET_GEN)$(PYTHON) $(top_srcdir)/tools/glib-ginterface-gen.py \
+ $(AM_V_GEN)$(PYTHON) $(top_srcdir)/tools/glib-ginterface-gen.py \
--filename=_gen/svc \
--signal-marshal-prefix=NOT_NEEDED \
$< Test_Svc_
@@ -215,4 +214,4 @@ _gen/svc.c _gen/svc.h: with-properties.xml \
_gen/errors-check.h: $(top_srcdir)/spec/errors.xml \
$(top_srcdir)/tools/glib-errors-check-gen.py
$(mkdir_p) _gen
- $(QUIET_GEN)$(PYTHON) $(top_srcdir)/tools/glib-errors-check-gen.py $< > $@
+ $(AM_V_GEN)$(PYTHON) $(top_srcdir)/tools/glib-errors-check-gen.py $< > $@
diff --git a/tests/dbus/account-manager.c b/tests/dbus/account-manager.c
index 7aa373adf..1f152b7d4 100644
--- a/tests/dbus/account-manager.c
+++ b/tests/dbus/account-manager.c
@@ -56,6 +56,28 @@ test_new (Test *test,
test->am = tp_account_manager_new (test->dbus);
}
+static void
+test_dup (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ TpAccountManager *one, *two;
+ TpDBusDaemon *dbus_one, *dbus_two;
+
+ one = tp_account_manager_dup ();
+ two = tp_account_manager_dup ();
+
+ g_assert (one == two);
+
+ dbus_one = tp_dbus_daemon_dup (NULL);
+ dbus_two = tp_proxy_get_dbus_daemon (one);
+
+ g_assert (dbus_one == dbus_two);
+
+ g_object_unref (dbus_one);
+ g_object_unref (two);
+ g_object_unref (one);
+}
+
int
main (int argc,
char **argv)
@@ -64,6 +86,7 @@ main (int argc,
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/am/new", Test, NULL, setup, test_new, teardown);
+ g_test_add ("/am/dup", Test, NULL, setup, test_dup, teardown);
return g_test_run ();
}
diff --git a/tests/dbus/account.c b/tests/dbus/account.c
index aeb876215..70c0b6d72 100644
--- a/tests/dbus/account.c
+++ b/tests/dbus/account.c
@@ -10,6 +10,62 @@
#include <telepathy-glib/account.h>
#include <telepathy-glib/debug.h>
+#include <telepathy-glib/defs.h>
+
+static void
+test_parse_failure (gconstpointer test_data)
+{
+ GError *error = NULL;
+
+ g_assert (!tp_account_parse_object_path (test_data, NULL, NULL, NULL,
+ &error));
+ g_assert (error != NULL);
+ g_error_free (error);
+}
+
+typedef struct {
+ const gchar *path;
+ const gchar *cm;
+ const gchar *protocol;
+ const gchar *account_id;
+} TestParseData;
+
+static TestParseData *
+test_parse_data_new (const gchar *path,
+ const gchar *cm,
+ const gchar *protocol,
+ const gchar *account_id)
+{
+ TestParseData *t = g_slice_new (TestParseData);
+
+ t->path = path;
+ t->cm = cm;
+ t->protocol = protocol;
+ t->account_id = account_id;
+
+ return t;
+}
+
+static void
+test_parse_success (gconstpointer test_data)
+{
+ TestParseData *t = (TestParseData *) test_data;
+ gchar *cm, *protocol, *account_id;
+ GError *error = NULL;
+
+ g_assert (tp_account_parse_object_path (t->path, &cm, &protocol, &account_id,
+ &error));
+ g_assert_no_error (error);
+ g_assert_cmpstr (cm, ==, t->cm);
+ g_assert_cmpstr (protocol, ==, t->protocol);
+ g_assert_cmpstr (account_id, ==, t->account_id);
+
+ g_free (cm);
+ g_free (protocol);
+ g_free (account_id);
+
+ g_slice_free (TestParseData, t);
+}
typedef struct {
GMainLoop *mainloop;
@@ -23,9 +79,6 @@ static void
setup (Test *test,
gconstpointer data)
{
- g_type_init ();
- tp_debug_set_flags ("all");
-
test->mainloop = g_main_loop_new (NULL, FALSE);
test->dbus = tp_dbus_daemon_dup (NULL);
g_assert (test->dbus != NULL);
@@ -62,7 +115,7 @@ test_new (Test *test,
g_assert (test->account == NULL);
test->account = tp_account_new (test->dbus,
- "/org/freedesktop/Telepathy/Account/whatever", NULL);
+ "/org/freedesktop/Telepathy/Account/what/ev/er", NULL);
g_assert (test->account != NULL);
}
@@ -70,9 +123,49 @@ int
main (int argc,
char **argv)
{
+ g_type_init ();
+ tp_debug_set_flags ("all");
+
g_test_init (&argc, &argv, NULL);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
+ g_test_add_data_func ("/account/parse/spaces",
+ "this is not an object path", test_parse_failure);
+ g_test_add_data_func ("/account/parse/no-prefix",
+ "/this/is/not/an/account/path", test_parse_failure);
+ g_test_add_data_func ("/account/parse/too-few-components",
+ "/org/freedesktop/Telepathy/Account/wrong", test_parse_failure);
+ g_test_add_data_func ("/account/parse/too-many-components",
+ "/org/freedesktop/Telepathy/Account/a/b/c/d", test_parse_failure);
+ g_test_add_data_func ("/account/parse/illegal-components",
+ "/org/freedesktop/Telepathy/Account/1/2/3", test_parse_failure);
+
+ g_test_add_data_func ("/account/parse/legal",
+ test_parse_data_new (
+ TP_ACCOUNT_OBJECT_PATH_BASE "gabble/jabber/badgers",
+ "gabble", "jabber", "badgers"),
+ test_parse_success);
+ g_test_add_data_func ("/account/parse/hyphenated-protocol",
+ test_parse_data_new (
+ TP_ACCOUNT_OBJECT_PATH_BASE "salut/local_xmpp/badgers",
+ "salut", "local-xmpp", "badgers"),
+ test_parse_success);
+ g_test_add_data_func ("/account/parse/wrongly-escaped-protocol",
+ test_parse_data_new (
+ TP_ACCOUNT_OBJECT_PATH_BASE "salut/local_2dxmpp/badgers",
+ "salut", "local-xmpp", "badgers"),
+ test_parse_success);
+ g_test_add_data_func ("/account/parse/wrongly-escaped-corner-case",
+ test_parse_data_new (
+ TP_ACCOUNT_OBJECT_PATH_BASE "salut/local_2d/badgers",
+ "salut", "local-", "badgers"),
+ test_parse_success);
+ g_test_add_data_func ("/account/parse/underscored-account",
+ test_parse_data_new (
+ TP_ACCOUNT_OBJECT_PATH_BASE "haze/msn/_thisseemsunlikely",
+ "haze", "msn", "_thisseemsunlikely"),
+ test_parse_success);
+
g_test_add ("/account/new", Test, NULL, setup, test_new, teardown);
return g_test_run ();
diff --git a/tools/Makefile.am b/tools/Makefile.am
index a817df4e0..63260d584 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,5 +1,3 @@
-include $(top_srcdir)/tools/shave.mk
-
abs_top_builddir = @abs_top_builddir@
noinst_SCRIPTS = telepathy-glib-env
@@ -42,23 +40,23 @@ CLEANFILES = libtpcodegen.pyc libtpcodegen.pyo libglibcodegen.pyc libglibcodegen
all: $(EXTRA_DIST)
libglibcodegen.py: libtpcodegen.py
- $(QUIET_GEN)touch $@
+ $(AM_V_GEN)touch $@
c-constants-gen.py: libglibcodegen.py
- $(QUIET_GEN)touch $@
+ $(AM_V_GEN)touch $@
glib-client-marshaller-gen.py: libglibcodegen.py
- $(QUIET_GEN)touch $@
+ $(AM_V_GEN)touch $@
glib-errors-enum-body-gen.py: libglibcodegen.py
- $(QUIET_GEN)touch $@
+ $(AM_V_GEN)touch $@
glib-errors-enum-header-gen.py: libglibcodegen.py
- $(QUIET_GEN)touch $@
+ $(AM_V_GEN)touch $@
glib-ginterface-gen.py: libglibcodegen.py
- $(QUIET_GEN)touch $@
+ $(AM_V_GEN)touch $@
glib-gtypes-generator.py: libglibcodegen.py
- $(QUIET_GEN)touch $@
+ $(AM_V_GEN)touch $@
glib-interfaces-gen.py: libglibcodegen.py
- $(QUIET_GEN)touch $@
+ $(AM_V_GEN)touch $@
glib-signals-marshal-gen.py: libglibcodegen.py
- $(QUIET_GEN)touch $@
+ $(AM_V_GEN)touch $@
TELEPATHY_SPEC_SRCDIR = $(top_srcdir)/../telepathy-spec
maintainer-update-from-telepathy-spec: