diff options
author | Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> | 2011-03-18 17:12:32 -0400 |
---|---|---|
committer | Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> | 2011-03-25 14:03:03 -0400 |
commit | 9af6d6177c9659db9d0df6a6ddd9dfa83b48c2f2 (patch) | |
tree | eeed0938767fb1f0f2f8eba3b0fd28e9698ef6ea | |
parent | 07560a5c0d0ea5281bc62b1651ab3e709e2980df (diff) |
Add support for TplCallChannel
-rw-r--r-- | data/Logger.client | 8 | ||||
-rw-r--r-- | src/telepathy-logger.c | 5 | ||||
-rw-r--r-- | telepathy-logger/Makefile.am | 2 | ||||
-rw-r--r-- | telepathy-logger/call-channel-internal.h | 71 | ||||
-rw-r--r-- | telepathy-logger/call-channel.c | 761 | ||||
-rw-r--r-- | telepathy-logger/observer.c | 18 | ||||
-rw-r--r-- | telepathy-logger/tpl-marshal.list | 2 |
7 files changed, 867 insertions, 0 deletions
diff --git a/data/Logger.client b/data/Logger.client index a28d298..e76023d 100644 --- a/data/Logger.client +++ b/data/Logger.client @@ -13,5 +13,13 @@ org.freedesktop.Telepathy.Channel.TargetHandleType u=2 org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.StreamedMedia org.freedesktop.Telepathy.Channel.TargetHandleType u=1 +[org.freedesktop.Telepathy.Client.Observer.ObserverChannelFilter 2] +org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Call.DRAFT +org.freedesktop.Telepathy.Channel.TargetHandleType u=1 + +[org.freedesktop.Telepathy.Client.Observer.ObserverChannelFilter 2] +org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Call.DRAFT +org.freedesktop.Telepathy.Channel.TargetHandleType u=2 + [org.freedesktop.Telepathy.Client.Observer] Recover=true diff --git a/src/telepathy-logger.c b/src/telepathy-logger.c index 3e9b42f..57dbd46 100644 --- a/src/telepathy-logger.c +++ b/src/telepathy-logger.c @@ -25,6 +25,7 @@ #include <telepathy-glib/telepathy-glib.h> #include <telepathy-glib/debug-sender.h> +#include <telepathy-logger/call-channel-internal.h> #include <telepathy-logger/channel-factory-internal.h> #include <telepathy-logger/text-channel-internal.h> #include <telepathy-logger/observer-internal.h> @@ -178,6 +179,10 @@ main (int argc, (TplChannelConstructor) _tpl_streamed_media_channel_new); DEBUG ("- TplStreamedMediaChannel registered."); + _tpl_channel_factory_add ("org.freedesktop.Telepathy.Channel.Type.Call.DRAFT", + (TplChannelConstructor) _tpl_call_channel_new); + DEBUG ("- TplCallChannel registered."); + observer = _tpl_observer_new (); DEBUG ("Registering channel factory into TplObserver"); _tpl_observer_set_channel_factory (observer, _tpl_channel_factory_build); diff --git a/telepathy-logger/Makefile.am b/telepathy-logger/Makefile.am index 657002d..ab35f93 100644 --- a/telepathy-logger/Makefile.am +++ b/telepathy-logger/Makefile.am @@ -45,6 +45,8 @@ BUILT_SOURCES = \ libtelepathy_logger_la_SOURCES = \ action-chain.c \ action-chain-internal.h \ + call-channel.c \ + call-channel-internal.h \ call-event.c \ call-event-internal.h \ channel-internal.h \ diff --git a/telepathy-logger/call-channel-internal.h b/telepathy-logger/call-channel-internal.h new file mode 100644 index 0000000..bebb8c8 --- /dev/null +++ b/telepathy-logger/call-channel-internal.h @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2011 Collabora Ltd. + * + * 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 + * + * Authors: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> + */ + +#ifndef __TPL_CALL_CHANNEL_H__ +#define __TPL_CALL_CHANNEL_H__ + +#include <glib-object.h> +#include <telepathy-glib/telepathy-glib.h> + +#include <telepathy-logger/channel-internal.h> + +G_BEGIN_DECLS +#define TPL_TYPE_CALL_CHANNEL (_tpl_call_channel_get_type ()) +#define TPL_CALL_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TPL_TYPE_CALL_CHANNEL, TplCallChannel)) +#define TPL_CALL_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TPL_TYPE_CALL_CHANNEL, TplCallChannelClass)) +#define TPL_IS_CALL_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TPL_TYPE_CALL_CHANNEL)) +#define TPL_IS_CALL_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TPL_TYPE_CALL_CHANNEL)) +#define TPL_CALL_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TPL_TYPE_CALL_CHANNEL, TplCallChannelClass)) + +#define TPL_CALL_CHANNEL_ERROR \ + g_quark_from_static_string ("tpl-call-channel-error-quark") + +typedef enum +{ + /* generic error */ + TPL_CALL_CHANNEL_ERROR_FAILED, + TPL_CALL_CHANNEL_ERROR_MISSING_TARGET_CONTACT, +} TplCallChannelError; + +typedef struct _TplCallChannelPriv TplCallChannelPriv; +typedef struct +{ + TpChannel parent; + + /* private */ + TplCallChannelPriv *priv; +} TplCallChannel; + +typedef struct +{ + TpChannelClass parent_class; +} TplCallChannelClass; + +GType _tpl_call_channel_get_type (void); + +TplCallChannel * _tpl_call_channel_new (TpConnection *conn, + const gchar *object_path, + GHashTable *tp_chan_props, + TpAccount *account, + GError **error); + +G_END_DECLS +#endif /* __TPL_CALL_CHANNEL_H__ */ diff --git a/telepathy-logger/call-channel.c b/telepathy-logger/call-channel.c new file mode 100644 index 0000000..d785602 --- /dev/null +++ b/telepathy-logger/call-channel.c @@ -0,0 +1,761 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2011 Collabora Ltd. + * + * 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 + * + * Authors: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> + */ + +#include "config.h" +#include "call-channel-internal.h" + +#include <glib.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/proxy-subclass.h> + +#include "action-chain-internal.h" +#include "call-event.h" +#include "call-event-internal.h" +#include "channel-internal.h" +#include "entity-internal.h" +#include "event-internal.h" +#include "log-manager-internal.h" +#include "observer-internal.h" +#include "tpl-marshal.h" +#include "util-internal.h" + +#define DEBUG_FLAG TPL_DEBUG_CHANNEL +#include "debug-internal.h" + +#define TPL_IFACE_CHANNEL_TYPE_CALL \ + "org.freedesktop.Telepathy.Channel.Type.Call.DRAFT" +#define TPL_IFACE_QUARK_CHANNEL_TYPE_CALL tpl_get_channel_type_call_interface () + +typedef enum +{ + PENDING_INITIATOR_STATE = 1, + PENDING_RECEIVER_STATE, + ACCEPTED_STATE, + ENDED_STATE, +} CallState; + +struct _TplCallChannelPriv +{ + TpAccount *account; + GHashTable *entities; + TplEntity *sender; + TplEntity *receiver; + GDateTime *timestamp; + GTimer *timer; + gboolean timer_started; + TplEntity *end_actor; + TplCallEndReason end_reason; + gchar *detailed_end_reason; +}; + +static TpContactFeature features[3] = { + TP_CONTACT_FEATURE_ALIAS, + TP_CONTACT_FEATURE_PRESENCE, + TP_CONTACT_FEATURE_AVATAR_TOKEN +}; + +static void tpl_call_channel_iface_init (TplChannelInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (TplCallChannel, _tpl_call_channel, + TP_TYPE_CHANNEL, + G_IMPLEMENT_INTERFACE (TPL_TYPE_CHANNEL, tpl_call_channel_iface_init)) + + +static GQuark +tpl_get_channel_type_call_interface (void) +{ + static GQuark interface = 0; + + if (G_UNLIKELY (interface == 0)) + interface = g_quark_from_static_string (TPL_IFACE_CHANNEL_TYPE_CALL); + + return interface; +} + + +static void +proxy_prepared_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + TplActionChain *ctx = user_data; + GError *error = NULL; + + if (!tp_proxy_prepare_finish (source, result, &error)) + { + _tpl_action_chain_terminate (ctx, error); + g_error_free (error); + return; + } + + _tpl_action_chain_continue (ctx); +} + + +static void +pendingproc_prepare_tp_connection (TplActionChain *ctx, + gpointer user_data) +{ + TplCallChannel *chan = _tpl_action_chain_get_object (ctx); + TpConnection *conn = tp_channel_borrow_connection (TP_CHANNEL (chan)); + GQuark conn_features[] = { TP_CONNECTION_FEATURE_CORE, 0 }; + + tp_proxy_prepare_async (conn, conn_features, proxy_prepared_cb, ctx); +} + + +static void +pendingproc_prepare_tp_channel (TplActionChain *ctx, + gpointer user_data) +{ + TplCallChannel *chan = _tpl_action_chain_get_object (ctx); + GQuark chan_features[] = { + TP_CHANNEL_FEATURE_CORE, + TP_CHANNEL_FEATURE_GROUP, + 0 + }; + + tp_proxy_prepare_async (chan, chan_features, proxy_prepared_cb, ctx); +} + + +static void +get_remote_contacts_cb (TpConnection *connection, + guint n_contacts, + TpContact *const *contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + TpChannel *chan = TP_CHANNEL (weak_object); + TplCallChannelPriv *priv = TPL_CALL_CHANNEL (weak_object)->priv; + TplActionChain *ctx = user_data; + guint i; + + if (error != NULL) + { + DEBUG ("Failed to get remote contacts: %s", error->message); + + if (ctx != NULL) + _tpl_action_chain_terminate (ctx, error); + return; + } + + for (i = 0; i < n_contacts; i++) + { + TpContact *contact = contacts[i]; + TpHandle handle = tp_contact_get_handle (contact); + + g_hash_table_insert (priv->entities, GUINT_TO_POINTER (handle), + tpl_entity_new_from_tp_contact (contact, TPL_ENTITY_CONTACT)); + } + + if (ctx != NULL) + { + TplEntity *target; + TpHandle target_handle; + + target_handle = tp_channel_get_handle (chan, NULL); + + target = g_hash_table_lookup (priv->entities, + GUINT_TO_POINTER (target_handle)); + + /* Should not happen, but as we never know ... */ + if (target == NULL) + { + GError *new_error = NULL; + new_error = g_error_new (TPL_CALL_CHANNEL_ERROR, + TPL_CALL_CHANNEL_ERROR_MISSING_TARGET_CONTACT, + "Failed to resolve target contact"); + _tpl_action_chain_terminate (ctx, new_error); + g_error_free (new_error); + return; + } + + if (tp_channel_get_requested (chan)) + priv->receiver = g_object_ref (target); + else + priv->sender = g_object_ref (target); + + _tpl_action_chain_continue (ctx); + } +} + + +static void +get_call_members_cb (TpProxy *proxy, + const GValue *value, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + TplCallChannel *self = TPL_CALL_CHANNEL (weak_object); + TplActionChain *ctx = user_data; + GHashTable *members; + GArray *arr; + GList *it; + TpHandle target; + TpHandleType target_type; + + members = g_value_get_boxed (value); + arr = g_array_new (FALSE, FALSE, sizeof (TpHandle)); + + for (it = g_hash_table_get_keys (members); it != NULL; it = g_list_next (it)) + { + TpHandle remote = GPOINTER_TO_INT (it->data); + g_array_append_val (arr, remote); + } + + /* Get the contact of the TargetHandle */ + target = tp_channel_get_handle (TP_CHANNEL (self), &target_type); + + if (target_type == TP_HANDLE_TYPE_ROOM) + self->priv->receiver = tpl_entity_new_from_room_id ( + tp_channel_get_identifier (TP_CHANNEL (self))); + else if (!g_hash_table_lookup_extended (members, + GINT_TO_POINTER (target), NULL, NULL)) + g_array_append_val (arr, target); + + if (arr->len > 0) + { + TpConnection *tp_conn = tp_channel_borrow_connection (TP_CHANNEL (self)); + + tp_connection_get_contacts_by_handle (tp_conn, + arr->len, (TpHandle *) arr->data, + G_N_ELEMENTS (features), features, get_remote_contacts_cb, ctx, NULL, + G_OBJECT (self)); + + g_array_free (arr, TRUE); + } + else + { + g_array_free (arr, TRUE); + _tpl_action_chain_continue (ctx); + } +} + + +static void +pendingproc_get_remote_contacts (TplActionChain *ctx, + gpointer user_data) +{ + TplCallChannel *self = _tpl_action_chain_get_object (ctx); + + tp_cli_dbus_properties_call_get (TP_PROXY (self), -1, + TPL_IFACE_CHANNEL_TYPE_CALL, "CallMembers", + get_call_members_cb, ctx, NULL, + G_OBJECT (self)); +} + + +static void +get_self_contact_cb (TpConnection *connection, + guint n_contacts, + TpContact *const *contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + TplActionChain *ctx = user_data; + TplCallChannel *tpl_call = _tpl_action_chain_get_object (ctx); + TplChannel *tpl_chan = TPL_CHANNEL (tpl_call); + TpChannel *tp_chan = TP_CHANNEL (tpl_chan); + TplEntity *self; + gboolean is_room = FALSE; + + g_return_if_fail (TPL_IS_CALL_CHANNEL (tpl_call)); + + if (n_failed > 0) + { + TpConnection *tp_conn = tp_channel_borrow_connection (tp_chan); + const gchar *conn_path; + GError *new_error = NULL; + + conn_path = tp_proxy_get_object_path (TP_PROXY (tp_conn)); + + new_error = g_error_new (error->domain, error->code, + "Error resolving self handle for connection %s: %s)", + conn_path, error->message); + + _tpl_action_chain_terminate (ctx, new_error); + g_error_free (new_error); + return; + } + + self = tpl_entity_new_from_tp_contact (contacts[0], TPL_ENTITY_SELF); + + if (tpl_call->priv->receiver != NULL) + is_room = (tpl_entity_get_entity_type (tpl_call->priv->receiver) + == TPL_ENTITY_ROOM); + + if (tp_channel_get_requested (tp_chan) || is_room) + tpl_call->priv->sender = self; + else + tpl_call->priv->receiver = self; + + _tpl_action_chain_continue (ctx); +} + + +static void +pendingproc_get_local_contact (TplActionChain *ctx, + gpointer user_data) +{ + TplCallChannel *tpl_media = _tpl_action_chain_get_object (ctx); + TpChannel *chan = TP_CHANNEL (tpl_media); + TpConnection *tp_conn = tp_channel_borrow_connection (chan); + TpHandle my_handle; + + my_handle = tp_channel_group_get_self_handle (chan); + if (my_handle == 0) + my_handle = tp_connection_get_self_handle (tp_conn); + + tp_connection_get_contacts_by_handle (tp_conn, 1, &my_handle, + G_N_ELEMENTS (features), features, get_self_contact_cb, ctx, NULL, + G_OBJECT (tpl_media)); +} + +static TplCallEndReason +tp_to_tpl_end_reason (guint reason) +{ + switch (reason) + { + case 1: + return TPL_CALL_END_REASON_USER_REQUESTED; + case 3: + return TPL_CALL_END_REASON_NO_ANSWER; + case 0: + default: + return TPL_CALL_END_REASON_UNKNOWN; + } +} + + +static void +call_state_changed_cb (DBusGProxy *proxy, + CallState state, + guint flags, + GValueArray *reason, + GHashTable *details, + gpointer user_data) +{ + static const gchar *reasons[] = { + "Unknown", + "User Requested", + "No Answer" + }; + TplCallChannel *self = TPL_CALL_CHANNEL (user_data); + TplCallChannelPriv *priv = self->priv; + + switch (state) + { + case ACCEPTED_STATE: + { + DEBUG ("Moving to ACCEPTED_STATE, start_time=%li", + time (NULL)); + g_timer_start (priv->timer); + priv->timer_started = TRUE; + } + break; + + case ENDED_STATE: + { + TpHandle actor = g_value_get_uint ( + g_value_array_get_nth (reason, 0)); + TplCallEndReason end_reason = tp_to_tpl_end_reason ( + g_value_get_uint (g_value_array_get_nth (reason, 1))); + gchar *detailed_reason = g_value_dup_string ( + g_value_array_get_nth (reason, 2)); + + priv->end_actor = g_hash_table_lookup (priv->entities, + GUINT_TO_POINTER (actor)); + + if (priv->end_actor == NULL) + priv->end_actor = tpl_entity_new ("unknown", TPL_ENTITY_UNKNOWN, + NULL, NULL); + else + g_object_ref (priv->end_actor); + + priv->end_reason = end_reason; + + if (detailed_reason == NULL) + priv->detailed_end_reason = g_strdup (""); + else + priv->detailed_end_reason = detailed_reason; + + g_timer_stop (priv->timer); + + DEBUG ( + "Moving to ENDED_STATE, duration=%" G_GINT64_FORMAT " reason=%s details=%s", + (gint64) (priv->timer_started ? g_timer_elapsed (priv->timer, NULL) : -1), + reasons[priv->end_reason], + priv->detailed_end_reason); + } + break; + + default: + /* just wait */ + break; + } +} + + +static void +call_members_changed_cb (DBusGProxy *proxy, + GHashTable *flags_changed, + GArray *removed, + gpointer user_data) +{ + TplCallChannel *self = user_data; + TpChannel *chan = TP_CHANNEL (self); + GHashTableIter iter; + gpointer key; + GArray *added; + + added = g_array_new (FALSE, FALSE, sizeof (TpHandle)); + + g_hash_table_iter_init (&iter, flags_changed); + while (g_hash_table_iter_next (&iter, &key, NULL)) + { + TpHandle handle = GPOINTER_TO_INT (key); + g_array_append_val (added, handle); + } + + if (added->len > 0) + { + tp_connection_get_contacts_by_handle (tp_channel_borrow_connection (chan), + added->len, (TpHandle *) added->data, + G_N_ELEMENTS (features), features, get_remote_contacts_cb, NULL, NULL, + G_OBJECT (self)); + } + + g_array_free (added, TRUE); +} + + +static void +chan_members_changed_cb (TpChannel *chan, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + TpHandle actor, + guint reason, + gpointer user_data) +{ + TplCallChannel *self = user_data; + + if (added->len > 0) + { + tp_connection_get_contacts_by_handle (tp_channel_borrow_connection (chan), + added->len, (TpHandle *) added->data, + G_N_ELEMENTS (features), features, get_remote_contacts_cb, NULL, NULL, + G_OBJECT (self)); + } +} + + +static void +store_call (TplCallChannel *self) +{ + TplCallChannelPriv *priv = self->priv; + GError *error = NULL; + TplCallEvent *call_log; + TplLogManager *logmanager; + const gchar *channel_path = tp_proxy_get_object_path (TP_PROXY (self)); + GTimeSpan duration = -1; + + if (priv->timer_started) + duration = g_timer_elapsed (priv->timer, NULL); + + /* Initialize data for TplEntity */ + call_log = g_object_new (TPL_TYPE_CALL_EVENT, + /* TplEvent */ + "account", priv->account, + "channel-path", channel_path, + "receiver", priv->receiver, + "sender", priv->sender, + "timestamp", g_date_time_to_unix (priv->timestamp), + /* TplCallEvent */ + "duration", duration, + "end-actor", priv->end_actor, + "end-reason", priv->end_reason, + "detailed-end-reason", priv->detailed_end_reason, + NULL); + + logmanager = tpl_log_manager_dup_singleton (); + _tpl_log_manager_add_event (logmanager, TPL_EVENT (call_log), &error); + + if (error != NULL) + { + PATH_DEBUG (self, "TplCallChannel: %s", error->message); + g_error_free (error); + } + + g_object_unref (logmanager); + g_object_unref (call_log); +} + + +static void +channel_invalidated_cb (TpProxy *proxy, + guint domain, + gint code, + gchar *message, + gpointer user_data) +{ + TplChannel *tpl_chan = TPL_CHANNEL (user_data); + TplObserver *observer = _tpl_observer_new (); + + PATH_DEBUG (tpl_chan, "%s #%d %s", + g_quark_to_string (domain), code, message); + + store_call (TPL_CALL_CHANNEL (user_data)); + + if (!_tpl_observer_unregister_channel (observer, tpl_chan)) + PATH_DEBUG (tpl_chan, "Channel couldn't be unregistered correctly (BUG?)"); + + g_object_unref (observer); +} + + +static void +pendingproc_connect_signals (TplActionChain *ctx, + gpointer user_data) +{ + TplCallChannel *self = _tpl_action_chain_get_object (ctx); + DBusGProxy *proxy; + GError *error = NULL; + + proxy = tp_proxy_borrow_interface_by_id (TP_PROXY (self), + TPL_IFACE_QUARK_CHANNEL_TYPE_CALL, &error); + + if (proxy == NULL) + { + _tpl_action_chain_terminate (ctx, error); + g_error_free (error); + return; + } + + dbus_g_proxy_add_signal (proxy, + "CallStateChanged", + G_TYPE_UINT, + G_TYPE_UINT, + dbus_g_type_get_struct ("GValueArray", + G_TYPE_UINT, + G_TYPE_UINT, + G_TYPE_STRING, + G_TYPE_INVALID), + dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), + G_TYPE_INVALID); + + dbus_g_proxy_add_signal (proxy, + "CallMembersChanged", + dbus_g_type_get_map ("GHashTable", G_TYPE_UINT, G_TYPE_UINT), + DBUS_TYPE_G_UINT_ARRAY, + G_TYPE_INVALID); + + dbus_g_proxy_connect_signal (proxy, + "CallStateChanged", + G_CALLBACK (call_state_changed_cb), self, NULL); + + dbus_g_proxy_connect_signal (proxy, + "CallMembersChanged", + G_CALLBACK (call_members_changed_cb), self, NULL); + + tp_g_signal_connect_object (TP_CHANNEL (self), "group-members-changed", + G_CALLBACK (chan_members_changed_cb), self, 0); + + tp_g_signal_connect_object (TP_CHANNEL (self), "invalidated", + G_CALLBACK (channel_invalidated_cb), self, 0); + + _tpl_action_chain_continue (ctx); +} + + +static void +tpl_call_channel_prepare_async (TplChannel *chan, + GAsyncReadyCallback cb, + gpointer user_data) +{ + TplActionChain *actions; + + actions = _tpl_action_chain_new_async (G_OBJECT (chan), cb, user_data); + _tpl_action_chain_append (actions, pendingproc_connect_signals, NULL); + _tpl_action_chain_append (actions, pendingproc_prepare_tp_connection, NULL); + _tpl_action_chain_append (actions, pendingproc_prepare_tp_channel, NULL); + _tpl_action_chain_append (actions, pendingproc_get_remote_contacts, NULL); + _tpl_action_chain_append (actions, pendingproc_get_local_contact, NULL); + + _tpl_action_chain_continue (actions); +} + + +static gboolean +tpl_call_channel_prepare_finish (TplChannel *chan, + GAsyncResult *result, + GError **error) +{ + return _tpl_action_chain_new_finish (G_OBJECT (chan), result, error); +} + + +static void +tpl_call_channel_dispose (GObject *obj) +{ + TplCallChannelPriv *priv = TPL_CALL_CHANNEL (obj)->priv; + + tp_clear_object (&priv->account); + tp_clear_pointer (&priv->entities, g_hash_table_unref); + tp_clear_object (&priv->sender); + tp_clear_object (&priv->receiver); + tp_clear_pointer (&priv->timestamp, g_date_time_unref); + tp_clear_pointer (&priv->timer, g_timer_destroy); + tp_clear_object (&priv->end_actor); + tp_clear_pointer (&priv->detailed_end_reason, g_free); + + G_OBJECT_CLASS (_tpl_call_channel_parent_class)->dispose (obj); +} + + +static void +tpl_call_channel_finalize (GObject *obj) +{ + PATH_DEBUG (obj, "finalizing channel %p", obj); + + G_OBJECT_CLASS (_tpl_call_channel_parent_class)->finalize (obj); +} + + +static void +_tpl_call_channel_class_init (TplCallChannelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = tpl_call_channel_dispose; + object_class->finalize = tpl_call_channel_finalize; + + g_type_class_add_private (object_class, sizeof (TplCallChannelPriv)); + + dbus_g_object_register_marshaller (tpl_marshal_VOID__UINT_UINT_BOXED_BOXED, + G_TYPE_NONE, + G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOXED, G_TYPE_BOXED, + G_TYPE_INVALID); + + dbus_g_object_register_marshaller (tpl_marshal_VOID__BOXED_BOXED, + G_TYPE_NONE, + G_TYPE_BOXED, G_TYPE_BOXED, + G_TYPE_INVALID); +} + + +static void +tpl_call_channel_iface_init (TplChannelInterface *iface) +{ + iface->prepare_async = tpl_call_channel_prepare_async; + iface->prepare_finish = tpl_call_channel_prepare_finish; +} + + +static void +_tpl_call_channel_init (TplCallChannel *self) +{ + gchar *date; + + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + TPL_TYPE_CALL_CHANNEL, TplCallChannelPriv); + + self->priv->timestamp = g_date_time_new_now_utc (); + self->priv->timer = g_timer_new (); + + date = g_date_time_format (self->priv->timestamp, "%Y-%m-%d %H:%M:%S"); + DEBUG ("New call, timestamp=%s UTC", date); + g_free (date); + + self->priv->entities = g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) g_object_unref); +} + + +/** + * _tpl_call_channel_new + * @conn: TpConnection instance owning the channel + * @object_path: the channel's DBus path + * @tp_chan_props: channel's immutable properties, obtained for example by + * %tp_channel_borrow_immutable_properties() + * @account: TpAccount instance, related to the new #TplCallChannel + * @error: location of the GError, used in case a problem is raised while + * creating the channel + * + * Convenience function to create a new TPL Call Channel proxy. + * The returned #TplCallChannel is not guaranteed to be ready + * at the point of return. + * + * TplCallChannel is actually a subclass of #TpChannel implementing + * interface #TplChannel. Use #TpChannel methods, casting the #TplCallChannel + * instance to a TpChannel, to access TpChannel data/methods from it. + * + * TplCallChannel is usually created using + * #tpl_channel_factory_build, from within a #TplObserver singleton, + * when its Observer_Channel method is called by the Channel Dispatcher. + * + * Returns: the TplCallChannel instance or %NULL if + * @object_path is not valid. + */ +TplCallChannel * +_tpl_call_channel_new (TpConnection *conn, + const gchar *object_path, + GHashTable *tp_chan_props, + TpAccount *account, + GError **error) +{ + TpProxy *conn_proxy = TP_PROXY (conn); + TplCallChannel *self; + + /* Do what tpl_channel_new does + set TplCallChannel + * specific properties */ + + g_return_val_if_fail (TP_IS_CONNECTION (conn), NULL); + g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (!TPL_STR_EMPTY (object_path), NULL); + g_return_val_if_fail (tp_chan_props != NULL, NULL); + + if (!tp_dbus_check_valid_object_path (object_path, error)) + return NULL; + + self = g_object_new (TPL_TYPE_CALL_CHANNEL, + "connection", conn, + "dbus-daemon", conn_proxy->dbus_daemon, + "bus-name", conn_proxy->bus_name, + "object-path", object_path, + "handle-type", (guint) TP_UNKNOWN_HANDLE_TYPE, + "channel-properties", tp_chan_props, + NULL); + + self->priv->account = g_object_ref (account); + + return self; +} diff --git a/telepathy-logger/observer.c b/telepathy-logger/observer.c index 4110c25..5c676ca 100644 --- a/telepathy-logger/observer.c +++ b/telepathy-logger/observer.c @@ -389,6 +389,24 @@ _tpl_observer_init (TplObserver *self) TP_HANDLE_TYPE_CONTACT, NULL)); + /* Observe contact call channels */ + tp_base_client_take_observer_filter (TP_BASE_CLIENT (self), + tp_asv_new ( + TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, + "org.freedesktop.Telepathy.Channel.Type.Call.DRAFT", + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, + TP_HANDLE_TYPE_CONTACT, + NULL)); + + /* Observe room call channels */ + tp_base_client_take_observer_filter (TP_BASE_CLIENT (self), + tp_asv_new ( + TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, + "org.freedesktop.Telepathy.Channel.Type.Call.DRAFT", + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, + TP_HANDLE_TYPE_ROOM, + NULL)); + tp_base_client_set_observer_recover (TP_BASE_CLIENT (self), TRUE); } diff --git a/telepathy-logger/tpl-marshal.list b/telepathy-logger/tpl-marshal.list index 71e2781..2c852dd 100644 --- a/telepathy-logger/tpl-marshal.list +++ b/telepathy-logger/tpl-marshal.list @@ -1 +1,3 @@ # add marshallers here +VOID:UINT,UINT,BOXED,BOXED +VOID:BOXED,BOXED |