diff options
author | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2009-04-24 23:28:22 +0800 |
---|---|---|
committer | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2009-04-24 23:28:22 +0800 |
commit | f02d96379cb7043611d093921755d699e48689bb (patch) | |
tree | 4a7cb101ebe4295306f17f12f805e4672c30bff6 /libempathy | |
parent | c8d23985b7754541cab512992294c19f5c87cfaa (diff) | |
parent | d696d6cc31f672884382d5b8949be504cdc718a5 (diff) | |
download | gsoc2013-empathy-f02d96379cb7043611d093921755d699e48689bb.tar gsoc2013-empathy-f02d96379cb7043611d093921755d699e48689bb.tar.gz gsoc2013-empathy-f02d96379cb7043611d093921755d699e48689bb.tar.bz2 gsoc2013-empathy-f02d96379cb7043611d093921755d699e48689bb.tar.lz gsoc2013-empathy-f02d96379cb7043611d093921755d699e48689bb.tar.xz gsoc2013-empathy-f02d96379cb7043611d093921755d699e48689bb.tar.zst gsoc2013-empathy-f02d96379cb7043611d093921755d699e48689bb.zip |
Merge branch 'master' into tp-tube
Diffstat (limited to 'libempathy')
31 files changed, 2844 insertions, 4568 deletions
diff --git a/libempathy/Makefile.am b/libempathy/Makefile.am index f82f4cc0f..ba1f6f8c7 100644 --- a/libempathy/Makefile.am +++ b/libempathy/Makefile.am @@ -21,10 +21,9 @@ libempathy_la_SOURCES = \ empathy-account-manager.c \ empathy-chatroom.c \ empathy-chatroom-manager.c \ - empathy-call-factory.c \ - empathy-call-handler.c \ + empathy-call-factory.c \ + empathy-call-handler.c \ empathy-contact.c \ - empathy-contact-factory.c \ empathy-contact-groups.c \ empathy-contact-list.c \ empathy-contact-manager.c \ @@ -47,7 +46,6 @@ libempathy_la_SOURCES = \ empathy-tp-contact-factory.c \ empathy-tp-contact-list.c \ empathy-tp-file.c \ - empathy-tp-group.c \ empathy-tp-roomlist.c \ empathy-tp-tube.c \ empathy-tube-handler.c \ @@ -72,7 +70,6 @@ libempathy_headers = \ empathy-call-factory.h \ empathy-call-handler.h \ empathy-contact.h \ - empathy-contact-factory.h \ empathy-contact-groups.h \ empathy-contact-list.h \ empathy-contact-manager.h \ @@ -95,7 +92,6 @@ libempathy_headers = \ empathy-tp-contact-factory.h \ empathy-tp-contact-list.h \ empathy-tp-file.h \ - empathy-tp-group.h \ empathy-tp-roomlist.h \ empathy-tp-tube.h \ empathy-tube-handler.h \ diff --git a/libempathy/empathy-account-manager.c b/libempathy/empathy-account-manager.c index 5962a8676..b84543176 100644 --- a/libempathy/empathy-account-manager.c +++ b/libempathy/empathy-account-manager.c @@ -26,19 +26,24 @@ #include "empathy-marshal.h" #include "empathy-utils.h" +#define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT +#include <libempathy/empathy-debug.h> + #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountManager) typedef struct { McAccountMonitor *monitor; MissionControl *mc; - GHashTable *accounts; + GHashTable *accounts; /* McAccount -> AccountData */ + GHashTable *connections; /* TpConnection -> McAccount */ int connected; int connecting; gboolean dispose_run; } EmpathyAccountManagerPriv; typedef struct { + TpConnection *connection; McPresence presence; TpConnectionStatus status; gboolean is_enabled; @@ -54,6 +59,7 @@ enum { ACCOUNT_CHANGED, ACCOUNT_CONNECTION_CHANGED, ACCOUNT_PRESENCE_CHANGED, + NEW_CONNECTION, LAST_SIGNAL }; @@ -112,11 +118,75 @@ account_data_free (AccountData *data) g_source_remove (data->source_id); data->source_id = 0; } + if (data->connection != NULL) + { + g_object_unref (data->connection); + data->connection = NULL; + } g_slice_free (AccountData, data); } static void +connection_invalidated_cb (TpProxy *connection, + guint domain, + gint code, + gchar *message, + EmpathyAccountManager *manager) +{ + EmpathyAccountManagerPriv *priv = GET_PRIV (manager); + McAccount *account; + AccountData *data; + + DEBUG ("Message: %s", message); + + account = g_hash_table_lookup (priv->connections, connection); + g_assert (account != NULL); + + data = g_hash_table_lookup (priv->accounts, account); + g_assert (data != NULL); + + g_object_unref (data->connection); + data->connection = NULL; + + g_hash_table_remove (priv->connections, connection); +} + +static void +connection_ready_cb (TpConnection *connection, + const GError *error, + gpointer manager) +{ + /* Errors will be handled in invalidated callback */ + if (error != NULL) + return; + + g_signal_emit (manager, signals[NEW_CONNECTION], 0, connection); +} + +static void +account_manager_update_connection (EmpathyAccountManager *manager, + AccountData *data, + McAccount *account) +{ + EmpathyAccountManagerPriv *priv = GET_PRIV (manager); + + if (data->connection) + return; + + data->connection = mission_control_get_tpconnection (priv->mc, account, NULL); + if (data->connection != NULL) + { + g_signal_connect (data->connection, "invalidated", + G_CALLBACK (connection_invalidated_cb), manager); + g_hash_table_insert (priv->connections, g_object_ref (data->connection), + g_object_ref (account)); + tp_connection_call_when_ready (data->connection, connection_ready_cb, + manager); + } +} + +static void account_created_cb (McAccountMonitor *mon, gchar *account_name, EmpathyAccountManager *manager) @@ -132,6 +202,7 @@ account_created_cb (McAccountMonitor *mon, AccountData *data; data = account_data_new_default (priv->mc, account); + g_hash_table_insert (priv->accounts, g_object_ref (account), data); initial_status = mission_control_get_connection_status (priv->mc, account, NULL); @@ -141,12 +212,10 @@ account_created_cb (McAccountMonitor *mon, else if (initial_status == TP_CONNECTION_STATUS_CONNECTING) priv->connecting++; - /* the reference returned by mc_account_lookup is owned by the - * hash table. - */ - g_hash_table_insert (priv->accounts, account, data); + account_manager_update_connection (manager, data, account); g_signal_emit (manager, signals[ACCOUNT_CREATED], 0, account); + g_object_unref (account); } } @@ -313,10 +382,11 @@ account_status_changed_idle_cb (ChangedSignalData *signal_data) if (status == TP_CONNECTION_STATUS_CONNECTED) { - if (data->source_id > 0) { - g_source_remove (data->source_id); - data->source_id = 0; - } + if (data->source_id > 0) + { + g_source_remove (data->source_id); + data->source_id = 0; + } data->source_id = g_timeout_add_seconds (10, remove_data_timeout, @@ -325,6 +395,8 @@ account_status_changed_idle_cb (ChangedSignalData *signal_data) emit_connection = TRUE; } + account_manager_update_connection (manager, data, account); + if (emit_presence) g_signal_emit (manager, signals[ACCOUNT_PRESENCE_CHANGED], 0, account, presence, old_p); @@ -381,6 +453,8 @@ empathy_account_manager_init (EmpathyAccountManager *manager) empathy_account_equal, g_object_unref, (GDestroyNotify) account_data_free); + priv->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, + g_object_unref, g_object_unref); mc_accounts = mc_accounts_list (); @@ -412,6 +486,7 @@ do_finalize (GObject *obj) EmpathyAccountManagerPriv *priv = GET_PRIV (manager); g_hash_table_unref (priv->accounts); + g_hash_table_unref (priv->connections); G_OBJECT_CLASS (empathy_account_manager_parent_class)->finalize (obj); } @@ -562,6 +637,16 @@ empathy_account_manager_class_init (EmpathyAccountManagerClass *klass) 3, MC_TYPE_ACCOUNT, G_TYPE_INT, /* actual presence */ G_TYPE_INT); /* previous presence */ + + signals[NEW_CONNECTION] = + g_signal_new ("new-connection", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, TP_TYPE_CONNECTION); g_type_class_add_private (oclass, sizeof (EmpathyAccountManagerPriv)); } @@ -634,3 +719,91 @@ empathy_account_manager_get_count (EmpathyAccountManager *manager) return g_hash_table_size (priv->accounts); } + +McAccount * +empathy_account_manager_get_account (EmpathyAccountManager *manager, + TpConnection *connection) +{ + EmpathyAccountManagerPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0); + + priv = GET_PRIV (manager); + + return g_hash_table_lookup (priv->connections, connection); +} + +GList * +empathy_account_manager_dup_accounts (EmpathyAccountManager *manager) +{ + EmpathyAccountManagerPriv *priv; + GList *ret; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL); + + priv = GET_PRIV (manager); + + ret = g_hash_table_get_keys (priv->accounts); + g_list_foreach (ret, (GFunc) g_object_ref, NULL); + + return ret; +} + +/** + * empathy_account_manager_get_connection: + * @manager: a #EmpathyAccountManager + * @account: a #McAccount + * + * Get the connection of the accounts, or NULL if account is offline or the + * connection is not yet ready. This function does not return a new ref. + * + * Returns: the connection of the accounts. + **/ +TpConnection * +empathy_account_manager_get_connection (EmpathyAccountManager *manager, + McAccount *account) +{ + EmpathyAccountManagerPriv *priv; + AccountData *data; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL); + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + + priv = GET_PRIV (manager); + + data = g_hash_table_lookup (priv->accounts, account); + if (data && data->connection && tp_connection_is_ready (data->connection)) + return data->connection; + + return NULL; +} + +/** + * empathy_account_manager_dup_connections: + * @manager: a #EmpathyAccountManager + * + * Get a #GList of all ready #TpConnection. The list must be freed with + * g_list_free, and its elements must be unreffed. + * + * Returns: the list of connections + **/ +GList * +empathy_account_manager_dup_connections (EmpathyAccountManager *manager) +{ + EmpathyAccountManagerPriv *priv; + GHashTableIter iter; + gpointer connection; + GList *ret = NULL; + + g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL); + + priv = GET_PRIV (manager); + + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, &connection, NULL)) + if (connection != NULL && tp_connection_is_ready (connection)) + ret = g_list_prepend (ret, g_object_ref (connection)); + + return ret; +} + diff --git a/libempathy/empathy-account-manager.h b/libempathy/empathy-account-manager.h index b9aecb09f..ac90a34f7 100644 --- a/libempathy/empathy-account-manager.h +++ b/libempathy/empathy-account-manager.h @@ -61,6 +61,16 @@ gboolean empathy_account_manager_is_account_just_connected McAccount *account); int empathy_account_manager_get_count (EmpathyAccountManager *manager); +McAccount * empathy_account_manager_get_account + (EmpathyAccountManager *manager, + TpConnection *connection); +GList * empathy_account_manager_dup_accounts + (EmpathyAccountManager *manager); +TpConnection * empathy_account_manager_get_connection + (EmpathyAccountManager *manager, + McAccount *account); +GList * empathy_account_manager_dup_connections + (EmpathyAccountManager *manager); G_END_DECLS diff --git a/libempathy/empathy-call-handler.c b/libempathy/empathy-call-handler.c index 39d5899bd..820de6de5 100644 --- a/libempathy/empathy-call-handler.c +++ b/libempathy/empathy-call-handler.c @@ -402,30 +402,38 @@ empathy_call_handler_request_cb (EmpathyDispatchOperation *operation, empathy_dispatch_operation_claim (operation); } -static void -empathy_call_handler_contact_ready_cb (EmpathyContact *contact, - const GError *error, gpointer user_data, GObject *object) +void +empathy_call_handler_start_call (EmpathyCallHandler *handler) { - EmpathyCallHandler *self = EMPATHY_CALL_HANDLER (object); - EmpathyCallHandlerPriv *priv = GET_PRIV (self); + + EmpathyCallHandlerPriv *priv = GET_PRIV (handler); EmpathyDispatcher *dispatcher; - McAccount *account; + TpConnection *connection; GStrv allowed; GValue *value; - GHashTable *request = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, - (GDestroyNotify) tp_g_value_slice_free); + GHashTable *request; + + if (priv->call != NULL) + { + empathy_call_handler_start_tpfs (handler); + empathy_tp_call_accept_incoming_call (priv->call); + return; + } g_assert (priv->contact != NULL); dispatcher = empathy_dispatcher_dup_singleton (); - account = empathy_contact_get_account (priv->contact); - allowed = empathy_dispatcher_find_channel_class (dispatcher, account, + connection = empathy_contact_get_connection (priv->contact); + allowed = empathy_dispatcher_find_channel_class (dispatcher, connection, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, TP_HANDLE_TYPE_CONTACT); if (!tp_strv_contains ((const gchar * const *) allowed, TP_IFACE_CHANNEL ".TargetHandle")) return; + request = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, + (GDestroyNotify) tp_g_value_slice_free); + /* org.freedesktop.Telepathy.Channel.ChannelType */ value = tp_g_value_slice_new (G_TYPE_STRING); g_value_set_string (value, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); @@ -441,27 +449,9 @@ empathy_call_handler_contact_ready_cb (EmpathyContact *contact, g_value_set_uint (value, empathy_contact_get_handle (priv->contact)); g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandle", value); - empathy_dispatcher_create_channel (dispatcher, account, - request, empathy_call_handler_request_cb, self); + empathy_dispatcher_create_channel (dispatcher, connection, + request, empathy_call_handler_request_cb, handler); g_object_unref (dispatcher); } -void -empathy_call_handler_start_call (EmpathyCallHandler *handler) -{ - - EmpathyCallHandlerPriv *priv = GET_PRIV (handler); - - if (priv->call == NULL) - { - empathy_contact_call_when_ready (priv->contact, - EMPATHY_CONTACT_READY_HANDLE, - empathy_call_handler_contact_ready_cb, NULL, NULL, G_OBJECT (handler)); - } - else - { - empathy_call_handler_start_tpfs (handler); - empathy_tp_call_accept_incoming_call (priv->call); - } -} diff --git a/libempathy/empathy-chatroom-manager.c b/libempathy/empathy-chatroom-manager.c index 6765d9e48..e57dae7d3 100644 --- a/libempathy/empathy-chatroom-manager.c +++ b/libempathy/empathy-chatroom-manager.c @@ -1,7 +1,6 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2004-2007 Imendio AB - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -33,6 +32,7 @@ #include "empathy-tp-chat.h" #include "empathy-chatroom-manager.h" +#include "empathy-account-manager.h" #include "empathy-utils.h" #define DEBUG_FLAG EMPATHY_DEBUG_OTHER @@ -45,26 +45,19 @@ static EmpathyChatroomManager *chatroom_manager_singleton = NULL; #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyChatroomManager) -typedef struct { - GList *chatrooms; +typedef struct +{ + GList *chatrooms; gchar *file; + EmpathyAccountManager *account_manager; /* source id of the autosave timer */ gint save_timer_id; } EmpathyChatroomManagerPriv; -static void chatroom_manager_finalize (GObject *object); -static gboolean chatroom_manager_get_all (EmpathyChatroomManager *manager); -static gboolean chatroom_manager_file_parse (EmpathyChatroomManager *manager, - const gchar *filename); -static void chatroom_manager_parse_chatroom (EmpathyChatroomManager *manager, - xmlNodePtr node); -static gboolean chatroom_manager_file_save (EmpathyChatroomManager *manager); -static void reset_save_timeout (EmpathyChatroomManager *self); - enum { - CHATROOM_ADDED, - CHATROOM_REMOVED, - LAST_SIGNAL + CHATROOM_ADDED, + CHATROOM_REMOVED, + LAST_SIGNAL }; static guint signals[LAST_SIGNAL]; @@ -78,6 +71,238 @@ enum G_DEFINE_TYPE (EmpathyChatroomManager, empathy_chatroom_manager, G_TYPE_OBJECT); +/* + * API to save/load and parse the chatrooms file. + */ + +static gboolean +chatroom_manager_file_save (EmpathyChatroomManager *manager) +{ + EmpathyChatroomManagerPriv *priv; + xmlDocPtr doc; + xmlNodePtr root; + GList *l; + + priv = GET_PRIV (manager); + + doc = xmlNewDoc ("1.0"); + root = xmlNewNode (NULL, "chatrooms"); + xmlDocSetRootElement (doc, root); + + for (l = priv->chatrooms; l; l = l->next) { + EmpathyChatroom *chatroom; + xmlNodePtr node; + const gchar *account_id; + + chatroom = l->data; + + if (!empathy_chatroom_is_favorite (chatroom)) { + continue; + } + + account_id = mc_account_get_unique_name (empathy_chatroom_get_account (chatroom)); + + node = xmlNewChild (root, NULL, "chatroom", NULL); + xmlNewTextChild (node, NULL, "name", empathy_chatroom_get_name (chatroom)); + xmlNewTextChild (node, NULL, "room", empathy_chatroom_get_room (chatroom)); + xmlNewTextChild (node, NULL, "account", account_id); + xmlNewTextChild (node, NULL, "auto_connect", + empathy_chatroom_get_auto_connect (chatroom) ? "yes" : "no"); + } + + /* Make sure the XML is indented properly */ + xmlIndentTreeOutput = 1; + + DEBUG ("Saving file:'%s'", priv->file); + xmlSaveFormatFileEnc (priv->file, doc, "utf-8", 1); + xmlFreeDoc (doc); + + xmlCleanupParser (); + xmlMemoryDump (); + + return TRUE; +} + +static gboolean +save_timeout (EmpathyChatroomManager *self) +{ + EmpathyChatroomManagerPriv *priv = GET_PRIV (self); + + priv->save_timer_id = 0; + chatroom_manager_file_save (self); + + return FALSE; +} + +static void +reset_save_timeout (EmpathyChatroomManager *self) +{ + EmpathyChatroomManagerPriv *priv = GET_PRIV (self); + + if (priv->save_timer_id > 0) + { + g_source_remove (priv->save_timer_id); + } + + priv->save_timer_id = g_timeout_add_seconds (SAVE_TIMER, + (GSourceFunc) save_timeout, self); +} + +static void +chatroom_changed_cb (EmpathyChatroom *chatroom, + GParamSpec *spec, + EmpathyChatroomManager *self) +{ + reset_save_timeout (self); +} + +static void +add_chatroom (EmpathyChatroomManager *self, + EmpathyChatroom *chatroom) +{ + EmpathyChatroomManagerPriv *priv = GET_PRIV (self); + + priv->chatrooms = g_list_prepend (priv->chatrooms, g_object_ref (chatroom)); + + g_signal_connect (chatroom, "notify", + G_CALLBACK (chatroom_changed_cb), self); +} + +static void +chatroom_manager_parse_chatroom (EmpathyChatroomManager *manager, + xmlNodePtr node) +{ + EmpathyChatroomManagerPriv *priv; + EmpathyChatroom *chatroom; + McAccount *account; + xmlNodePtr child; + gchar *str; + gchar *name; + gchar *room; + gchar *account_id; + gboolean auto_connect; + + priv = GET_PRIV (manager); + + /* default values. */ + name = NULL; + room = NULL; + auto_connect = TRUE; + account_id = NULL; + + for (child = node->children; child; child = child->next) { + gchar *tag; + + if (xmlNodeIsText (child)) { + continue; + } + + tag = (gchar *) child->name; + str = (gchar *) xmlNodeGetContent (child); + + if (strcmp (tag, "name") == 0) { + name = g_strdup (str); + } + else if (strcmp (tag, "room") == 0) { + room = g_strdup (str); + } + else if (strcmp (tag, "auto_connect") == 0) { + if (strcmp (str, "yes") == 0) { + auto_connect = TRUE; + } else { + auto_connect = FALSE; + } + } + else if (strcmp (tag, "account") == 0) { + account_id = g_strdup (str); + } + + xmlFree (str); + } + + account = mc_account_lookup (account_id); + if (!account) { + g_free (name); + g_free (room); + g_free (account_id); + return; + } + + chatroom = empathy_chatroom_new_full (account, room, name, auto_connect); + empathy_chatroom_set_favorite (chatroom, TRUE); + add_chatroom (manager, chatroom); + g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); + + g_object_unref (account); + g_free (name); + g_free (room); + g_free (account_id); +} + +static gboolean +chatroom_manager_file_parse (EmpathyChatroomManager *manager, + const gchar *filename) +{ + EmpathyChatroomManagerPriv *priv; + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + xmlNodePtr chatrooms; + xmlNodePtr node; + + priv = GET_PRIV (manager); + + DEBUG ("Attempting to parse file:'%s'...", filename); + + ctxt = xmlNewParserCtxt (); + + /* Parse and validate the file. */ + doc = xmlCtxtReadFile (ctxt, filename, NULL, 0); + if (!doc) { + g_warning ("Failed to parse file:'%s'", filename); + xmlFreeParserCtxt (ctxt); + return FALSE; + } + + if (!empathy_xml_validate (doc, CHATROOMS_DTD_FILENAME)) { + g_warning ("Failed to validate file:'%s'", filename); + xmlFreeDoc(doc); + xmlFreeParserCtxt (ctxt); + return FALSE; + } + + /* The root node, chatrooms. */ + chatrooms = xmlDocGetRootElement (doc); + + for (node = chatrooms->children; node; node = node->next) { + if (strcmp ((gchar *) node->name, "chatroom") == 0) { + chatroom_manager_parse_chatroom (manager, node); + } + } + + DEBUG ("Parsed %d chatrooms", g_list_length (priv->chatrooms)); + + xmlFreeDoc(doc); + xmlFreeParserCtxt (ctxt); + + return TRUE; +} + +static gboolean +chatroom_manager_get_all (EmpathyChatroomManager *manager) +{ + EmpathyChatroomManagerPriv *priv; + + priv = GET_PRIV (manager); + + /* read file in */ + if (g_file_test (priv->file, G_FILE_TEST_EXISTS) && + !chatroom_manager_file_parse (manager, priv->file)) { + return FALSE; + } + + return TRUE; +} + static void empathy_chatroom_manager_get_property (GObject *object, guint property_id, @@ -119,6 +344,41 @@ empathy_chatroom_manager_set_property (GObject *object, } } +static void +chatroom_manager_finalize (GObject *object) +{ + EmpathyChatroomManager *self = EMPATHY_CHATROOM_MANAGER (object); + EmpathyChatroomManagerPriv *priv; + GList *l; + + priv = GET_PRIV (object); + + g_object_unref (priv->account_manager); + + if (priv->save_timer_id > 0) + { + /* have to save before destroy the object */ + g_source_remove (priv->save_timer_id); + priv->save_timer_id = 0; + chatroom_manager_file_save (self); + } + + for (l = priv->chatrooms; l != NULL; l = g_list_next (l)) + { + EmpathyChatroom *chatroom = l->data; + + g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb, + self); + + g_object_unref (chatroom); + } + + g_list_free (priv->chatrooms); + g_free (priv->file); + + (G_OBJECT_CLASS (empathy_chatroom_manager_parent_class)->finalize) (object); +} + static GObject * empathy_chatroom_manager_constructor (GType type, guint n_props, @@ -141,6 +401,8 @@ empathy_chatroom_manager_constructor (GType type, chatroom_manager_singleton = self; g_object_add_weak_pointer (obj, (gpointer) &chatroom_manager_singleton); + priv->account_manager = empathy_account_manager_dup_singleton (); + if (priv->file == NULL) { /* Set the default file path */ @@ -161,7 +423,7 @@ empathy_chatroom_manager_constructor (GType type, static void empathy_chatroom_manager_class_init (EmpathyChatroomManagerClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); GParamSpec *param_spec; object_class->constructor = empathy_chatroom_manager_constructor; @@ -181,201 +443,108 @@ empathy_chatroom_manager_class_init (EmpathyChatroomManagerClass *klass) G_PARAM_STATIC_BLURB); g_object_class_install_property (object_class, PROP_FILE, param_spec); - signals[CHATROOM_ADDED] = - g_signal_new ("chatroom-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, EMPATHY_TYPE_CHATROOM); - signals[CHATROOM_REMOVED] = - g_signal_new ("chatroom-removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, EMPATHY_TYPE_CHATROOM); - - g_type_class_add_private (object_class, - sizeof (EmpathyChatroomManagerPriv)); + signals[CHATROOM_ADDED] = g_signal_new ("chatroom-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, EMPATHY_TYPE_CHATROOM); + + signals[CHATROOM_REMOVED] = g_signal_new ("chatroom-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, EMPATHY_TYPE_CHATROOM); + + g_type_class_add_private (object_class, sizeof (EmpathyChatroomManagerPriv)); } static void empathy_chatroom_manager_init (EmpathyChatroomManager *manager) { - EmpathyChatroomManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, - EMPATHY_TYPE_CHATROOM_MANAGER, EmpathyChatroomManagerPriv); - - manager->priv = priv; -} - -static void -chatroom_changed_cb (EmpathyChatroom *chatroom, - GParamSpec *spec, - EmpathyChatroomManager *self) -{ - reset_save_timeout (self); -} - -static void -chatroom_manager_finalize (GObject *object) -{ - EmpathyChatroomManager *self = EMPATHY_CHATROOM_MANAGER (object); - EmpathyChatroomManagerPriv *priv; - GList *l; - - priv = GET_PRIV (object); - - if (priv->save_timer_id > 0) - { - /* have to save before destroy the object */ - g_source_remove (priv->save_timer_id); - priv->save_timer_id = 0; - chatroom_manager_file_save (self); - } - - for (l = priv->chatrooms; l != NULL; l = g_list_next (l)) - { - EmpathyChatroom *chatroom = l->data; + EmpathyChatroomManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, + EMPATHY_TYPE_CHATROOM_MANAGER, EmpathyChatroomManagerPriv); - g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb, - self); - - g_object_unref (chatroom); - } - - g_list_free (priv->chatrooms); - g_free (priv->file); - - (G_OBJECT_CLASS (empathy_chatroom_manager_parent_class)->finalize) (object); + manager->priv = priv; } EmpathyChatroomManager * empathy_chatroom_manager_dup_singleton (const gchar *file) { - return EMPATHY_CHATROOM_MANAGER (g_object_new (EMPATHY_TYPE_CHATROOM_MANAGER, - "file", file, NULL)); -} - -static gboolean -save_timeout (EmpathyChatroomManager *self) -{ - EmpathyChatroomManagerPriv *priv = GET_PRIV (self); - - priv->save_timer_id = 0; - chatroom_manager_file_save (self); - - return FALSE; -} - -static void -reset_save_timeout (EmpathyChatroomManager *self) -{ - EmpathyChatroomManagerPriv *priv = GET_PRIV (self); - - if (priv->save_timer_id > 0) - { - g_source_remove (priv->save_timer_id); - } - - priv->save_timer_id = g_timeout_add_seconds (SAVE_TIMER, - (GSourceFunc) save_timeout, self); -} - -static void -add_chatroom (EmpathyChatroomManager *self, - EmpathyChatroom *chatroom) -{ - EmpathyChatroomManagerPriv *priv = GET_PRIV (self); - - priv->chatrooms = g_list_prepend (priv->chatrooms, g_object_ref (chatroom)); - - g_signal_connect (chatroom, "notify", - G_CALLBACK (chatroom_changed_cb), self); + return EMPATHY_CHATROOM_MANAGER (g_object_new (EMPATHY_TYPE_CHATROOM_MANAGER, + "file", file, NULL)); } gboolean empathy_chatroom_manager_add (EmpathyChatroomManager *manager, EmpathyChatroom *chatroom) { - EmpathyChatroomManagerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), FALSE); - g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), FALSE); - - priv = GET_PRIV (manager); + EmpathyChatroomManagerPriv *priv; - /* don't add more than once */ - if (!empathy_chatroom_manager_find (manager, - empathy_chatroom_get_account (chatroom), - empathy_chatroom_get_room (chatroom))) { - gboolean favorite; + g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), FALSE); + g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), FALSE); - g_object_get (chatroom, "favorite", &favorite, NULL); + priv = GET_PRIV (manager); - add_chatroom (manager, chatroom); + /* don't add more than once */ + if (!empathy_chatroom_manager_find (manager, + empathy_chatroom_get_account (chatroom), + empathy_chatroom_get_room (chatroom))) + { + add_chatroom (manager, chatroom); - if (favorite) - { + if (empathy_chatroom_is_favorite (chatroom)) reset_save_timeout (manager); - } - g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); - - return TRUE; - } + g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); + return TRUE; + } - return FALSE; + return FALSE; } void empathy_chatroom_manager_remove (EmpathyChatroomManager *manager, - EmpathyChatroom *chatroom) + EmpathyChatroom *chatroom) { - EmpathyChatroomManagerPriv *priv; - GList *l; - - g_return_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager)); - g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); - - priv = GET_PRIV (manager); + EmpathyChatroomManagerPriv *priv; + GList *l; - for (l = priv->chatrooms; l; l = l->next) { - EmpathyChatroom *this_chatroom; + g_return_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager)); + g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); - this_chatroom = l->data; + priv = GET_PRIV (manager); - if (this_chatroom == chatroom || - empathy_chatroom_equal (chatroom, this_chatroom)) { - gboolean favorite; - priv->chatrooms = g_list_delete_link (priv->chatrooms, l); + for (l = priv->chatrooms; l; l = l->next) + { + EmpathyChatroom *this_chatroom; - g_object_get (chatroom, "favorite", &favorite, NULL); + this_chatroom = l->data; - if (favorite) + if (this_chatroom == chatroom || + empathy_chatroom_equal (chatroom, this_chatroom)) { - reset_save_timeout (manager); - } - - g_signal_emit (manager, signals[CHATROOM_REMOVED], 0, this_chatroom); + priv->chatrooms = g_list_delete_link (priv->chatrooms, l); + if (empathy_chatroom_is_favorite (chatroom)) + reset_save_timeout (manager); - g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb, - manager); + g_signal_emit (manager, signals[CHATROOM_REMOVED], 0, this_chatroom); + g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb, + manager); - g_object_unref (this_chatroom); - break; - } - } + g_object_unref (this_chatroom); + break; + } + } } EmpathyChatroom * empathy_chatroom_manager_find (EmpathyChatroomManager *manager, - McAccount *account, - const gchar *room) + McAccount *account, + const gchar *room) { EmpathyChatroomManagerPriv *priv; GList *l; @@ -457,7 +626,7 @@ empathy_chatroom_manager_get_count (EmpathyChatroomManager *manager, chatroom = l->data; if (empathy_account_equal (account, - empathy_chatroom_get_account (chatroom))) { + empathy_chatroom_get_account (chatroom))) { count++; } } @@ -465,225 +634,36 @@ empathy_chatroom_manager_get_count (EmpathyChatroomManager *manager, return count; } -/* - * API to save/load and parse the chatrooms file. - */ - -static gboolean -chatroom_manager_get_all (EmpathyChatroomManager *manager) -{ - EmpathyChatroomManagerPriv *priv; - - priv = GET_PRIV (manager); - - /* read file in */ - if (g_file_test (priv->file, G_FILE_TEST_EXISTS) && - !chatroom_manager_file_parse (manager, priv->file)) - return FALSE; - - return TRUE; -} - -static gboolean -chatroom_manager_file_parse (EmpathyChatroomManager *manager, - const gchar *filename) -{ - EmpathyChatroomManagerPriv *priv; - xmlParserCtxtPtr ctxt; - xmlDocPtr doc; - xmlNodePtr chatrooms; - xmlNodePtr node; - - priv = GET_PRIV (manager); - - DEBUG ("Attempting to parse file:'%s'...", filename); - - ctxt = xmlNewParserCtxt (); - - /* Parse and validate the file. */ - doc = xmlCtxtReadFile (ctxt, filename, NULL, 0); - if (!doc) { - g_warning ("Failed to parse file:'%s'", filename); - xmlFreeParserCtxt (ctxt); - return FALSE; - } - - if (!empathy_xml_validate (doc, CHATROOMS_DTD_FILENAME)) { - g_warning ("Failed to validate file:'%s'", filename); - xmlFreeDoc(doc); - xmlFreeParserCtxt (ctxt); - return FALSE; - } - - /* The root node, chatrooms. */ - chatrooms = xmlDocGetRootElement (doc); - - for (node = chatrooms->children; node; node = node->next) { - if (strcmp ((gchar *) node->name, "chatroom") == 0) { - chatroom_manager_parse_chatroom (manager, node); - } - } - - DEBUG ("Parsed %d chatrooms", g_list_length (priv->chatrooms)); - - xmlFreeDoc(doc); - xmlFreeParserCtxt (ctxt); - - return TRUE; -} - -static void -chatroom_manager_parse_chatroom (EmpathyChatroomManager *manager, - xmlNodePtr node) -{ - EmpathyChatroomManagerPriv *priv; - EmpathyChatroom *chatroom; - McAccount *account; - xmlNodePtr child; - gchar *str; - gchar *name; - gchar *room; - gchar *account_id; - gboolean auto_connect; - - priv = GET_PRIV (manager); - - /* default values. */ - name = NULL; - room = NULL; - auto_connect = TRUE; - account_id = NULL; - - for (child = node->children; child; child = child->next) { - gchar *tag; - - if (xmlNodeIsText (child)) { - continue; - } - - tag = (gchar *) child->name; - str = (gchar *) xmlNodeGetContent (child); - - if (strcmp (tag, "name") == 0) { - name = g_strdup (str); - } - else if (strcmp (tag, "room") == 0) { - room = g_strdup (str); - } - else if (strcmp (tag, "auto_connect") == 0) { - if (strcmp (str, "yes") == 0) { - auto_connect = TRUE; - } else { - auto_connect = FALSE; - } - } - else if (strcmp (tag, "account") == 0) { - account_id = g_strdup (str); - } - - xmlFree (str); - } - - account = mc_account_lookup (account_id); - if (!account) { - g_free (name); - g_free (room); - g_free (account_id); - return; - } - - chatroom = empathy_chatroom_new_full (account, room, name, auto_connect); - g_object_set (chatroom, "favorite", TRUE, NULL); - add_chatroom (manager, chatroom); - g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom); - - g_object_unref (account); - g_free (name); - g_free (room); - g_free (account_id); -} - -static gboolean -chatroom_manager_file_save (EmpathyChatroomManager *manager) -{ - EmpathyChatroomManagerPriv *priv; - xmlDocPtr doc; - xmlNodePtr root; - GList *l; - - priv = GET_PRIV (manager); - - doc = xmlNewDoc ("1.0"); - root = xmlNewNode (NULL, "chatrooms"); - xmlDocSetRootElement (doc, root); - - for (l = priv->chatrooms; l; l = l->next) { - EmpathyChatroom *chatroom; - xmlNodePtr node; - const gchar *account_id; - gboolean favorite; - - chatroom = l->data; - - g_object_get (chatroom, "favorite", &favorite, NULL); - if (!favorite) - continue; - - account_id = mc_account_get_unique_name (empathy_chatroom_get_account (chatroom)); - - node = xmlNewChild (root, NULL, "chatroom", NULL); - xmlNewTextChild (node, NULL, "name", empathy_chatroom_get_name (chatroom)); - xmlNewTextChild (node, NULL, "room", empathy_chatroom_get_room (chatroom)); - xmlNewTextChild (node, NULL, "account", account_id); - xmlNewTextChild (node, NULL, "auto_connect", empathy_chatroom_get_auto_connect (chatroom) ? "yes" : "no"); - } - - /* Make sure the XML is indented properly */ - xmlIndentTreeOutput = 1; - - DEBUG ("Saving file:'%s'", priv->file); - xmlSaveFormatFileEnc (priv->file, doc, "utf-8", 1); - xmlFreeDoc (doc); - - xmlCleanupParser (); - xmlMemoryDump (); - - return TRUE; -} - static void chatroom_manager_chat_destroyed_cb (EmpathyTpChat *chat, - gpointer user_data) + gpointer manager) { - EmpathyChatroomManager *manager = EMPATHY_CHATROOM_MANAGER (user_data); - McAccount *account = empathy_tp_chat_get_account (chat); - EmpathyChatroom *chatroom; - const gchar *roomname; - gboolean favorite; - - roomname = empathy_tp_chat_get_id (chat); - chatroom = empathy_chatroom_manager_find (manager, account, roomname); + EmpathyChatroomManagerPriv *priv = GET_PRIV (manager); + GList *l; - if (chatroom == NULL) - return; + for (l = priv->chatrooms; l; l = l->next) + { + EmpathyChatroom *chatroom = l->data; - g_object_set (chatroom, "tp-chat", NULL, NULL); - g_object_get (chatroom, "favorite", &favorite, NULL); + if (empathy_chatroom_get_tp_chat (chatroom) != chat) + continue; - if (!favorite) - { - /* Remove the chatroom from the list, unless it's in the list of - * favourites.. - * FIXME this policy should probably not be in libempathy */ - empathy_chatroom_manager_remove (manager, chatroom); + empathy_chatroom_set_tp_chat (chatroom, NULL); + if (!empathy_chatroom_is_favorite (chatroom)) + { + /* Remove the chatroom from the list, unless it's in the list of + * favourites.. + * FIXME this policy should probably not be in libempathy */ + empathy_chatroom_manager_remove (manager, chatroom); + } } } static void chatroom_manager_observe_channel_cb (EmpathyDispatcher *dispatcher, - EmpathyDispatchOperation *operation, gpointer user_data) + EmpathyDispatchOperation *operation, gpointer manager) { - EmpathyChatroomManager *manager = EMPATHY_CHATROOM_MANAGER (user_data); + EmpathyChatroomManagerPriv *priv = GET_PRIV (manager); EmpathyChatroom *chatroom; TpChannel *channel; EmpathyTpChat *chat; @@ -691,6 +671,7 @@ chatroom_manager_observe_channel_cb (EmpathyDispatcher *dispatcher, GQuark channel_type; TpHandleType handle_type; McAccount *account; + TpConnection *connection; channel_type = empathy_dispatch_operation_get_channel_type_id (operation); @@ -706,7 +687,9 @@ chatroom_manager_observe_channel_cb (EmpathyDispatcher *dispatcher, chat = EMPATHY_TP_CHAT ( empathy_dispatch_operation_get_channel_wrapper (operation)); - account = empathy_tp_chat_get_account (chat); + connection = empathy_tp_chat_get_connection (chat); + account = empathy_account_manager_get_account (priv->account_manager, + connection); roomname = empathy_tp_chat_get_id (chat); @@ -716,13 +699,13 @@ chatroom_manager_observe_channel_cb (EmpathyDispatcher *dispatcher, { chatroom = empathy_chatroom_new_full (account, roomname, roomname, FALSE); - g_object_set (G_OBJECT (chatroom), "tp-chat", chat, NULL); + empathy_chatroom_set_tp_chat (chatroom, chat); empathy_chatroom_manager_add (manager, chatroom); g_object_unref (chatroom); } else { - g_object_set (G_OBJECT (chatroom), "tp-chat", chat, NULL); + empathy_chatroom_set_tp_chat (chatroom, chat); } /* A TpChat is always destroyed as it only gets unreffed after the channel diff --git a/libempathy/empathy-chatroom.c b/libempathy/empathy-chatroom.c index 8ffd8a51e..6575bb998 100644 --- a/libempathy/empathy-chatroom.c +++ b/libempathy/empathy-chatroom.c @@ -111,17 +111,14 @@ empathy_chatroom_class_init (EmpathyChatroomClass *klass) FALSE, G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_FAVORITE, - g_param_spec_boolean ("favorite", - "Favorite", - "TRUE if the chatroom is in user's favorite list", - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); + g_object_class_install_property (object_class, + PROP_FAVORITE, + g_param_spec_boolean ("favorite", + "Favorite", + "TRUE if the chatroom is in user's favorite list", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_TP_CHAT, @@ -284,30 +281,14 @@ chatroom_set_property (GObject *object, empathy_chatroom_set_auto_connect (EMPATHY_CHATROOM (object), g_value_get_boolean (value)); break; - case PROP_FAVORITE: - priv->favorite = g_value_get_boolean (value); - if (!priv->favorite) - { - empathy_chatroom_set_auto_connect (EMPATHY_CHATROOM (object), - FALSE); - } - break; - case PROP_TP_CHAT: { - GObject *chat = g_value_dup_object (value); - - if (chat == (GObject *) priv->tp_chat) - break; - - g_assert (chat == NULL || priv->tp_chat == NULL); - - if (priv->tp_chat != NULL) { - g_object_unref (priv->tp_chat); - priv->tp_chat = NULL; - } else { - priv->tp_chat = EMPATHY_TP_CHAT (chat); - } + case PROP_FAVORITE: + empathy_chatroom_set_favorite (EMPATHY_CHATROOM (object), + g_value_get_boolean (value)); + break; + case PROP_TP_CHAT: + empathy_chatroom_set_tp_chat (EMPATHY_CHATROOM (object), + g_value_get_object (value)); break; - } case PROP_SUBJECT: empathy_chatroom_set_subject (EMPATHY_CHATROOM (object), g_value_get_string (value)); @@ -476,12 +457,11 @@ empathy_chatroom_set_auto_connect (EmpathyChatroom *chatroom, priv->auto_connect = auto_connect; - if (priv->auto_connect) - { - /* auto_connect implies favorite */ - priv->favorite = TRUE; - g_object_notify (G_OBJECT (chatroom), "favorite"); - } + if (priv->auto_connect) { + /* auto_connect implies favorite */ + priv->favorite = TRUE; + g_object_notify (G_OBJECT (chatroom), "favorite"); + } g_object_notify (G_OBJECT (chatroom), "auto-connect"); } @@ -504,12 +484,13 @@ empathy_chatroom_equal (gconstpointer v1, room_a = empathy_chatroom_get_room (EMPATHY_CHATROOM (v1)); room_b = empathy_chatroom_get_room (EMPATHY_CHATROOM (v2)); - return empathy_account_equal (account_a, account_b) && !tp_strdiff (room_a, - room_b); + return empathy_account_equal (account_a, account_b) && + !tp_strdiff (room_a, room_b); } EmpathyTpChat * -empathy_chatroom_get_tp_chat (EmpathyChatroom *chatroom) { +empathy_chatroom_get_tp_chat (EmpathyChatroom *chatroom) +{ EmpathyChatroomPriv *priv; g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), NULL); @@ -631,3 +612,59 @@ empathy_chatroom_set_invite_only (EmpathyChatroom *chatroom, g_object_notify (G_OBJECT (chatroom), "invite-only"); } +void +empathy_chatroom_set_tp_chat (EmpathyChatroom *chatroom, + EmpathyTpChat *tp_chat) +{ + EmpathyChatroomPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); + g_return_if_fail (tp_chat == NULL || EMPATHY_IS_TP_CHAT (tp_chat)); + + priv = GET_PRIV (chatroom); + + if (priv->tp_chat == tp_chat) { + return; + } + + if (priv->tp_chat != NULL) { + g_object_unref (priv->tp_chat); + } + + priv->tp_chat = tp_chat ? g_object_ref (tp_chat) : NULL; + g_object_notify (G_OBJECT (chatroom), "tp-chat"); +} + +gboolean +empathy_chatroom_is_favorite (EmpathyChatroom *chatroom) +{ + EmpathyChatroomPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), FALSE); + + priv = GET_PRIV (chatroom); + + return priv->favorite; +} + +void +empathy_chatroom_set_favorite (EmpathyChatroom *chatroom, + gboolean favorite) +{ + EmpathyChatroomPriv *priv; + + g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom)); + + priv = GET_PRIV (chatroom); + + if (priv->favorite == favorite) { + return; + } + + priv->favorite = favorite; + if (!priv->favorite) { + empathy_chatroom_set_auto_connect (chatroom, FALSE); + } + g_object_notify (G_OBJECT (chatroom), "favorite"); +} + diff --git a/libempathy/empathy-chatroom.h b/libempathy/empathy-chatroom.h index 08e3bc1eb..560517d48 100644 --- a/libempathy/empathy-chatroom.h +++ b/libempathy/empathy-chatroom.h @@ -84,6 +84,11 @@ void empathy_chatroom_set_invite_only (EmpathyChatroom *chatroom, gboolean empathy_chatroom_equal (gconstpointer v1, gconstpointer v2); EmpathyTpChat * empathy_chatroom_get_tp_chat (EmpathyChatroom *chatroom); +void empathy_chatroom_set_tp_chat (EmpathyChatroom *chatroom, + EmpathyTpChat *tp_chat); +gboolean empathy_chatroom_is_favorite (EmpathyChatroom *chatroom); +void empathy_chatroom_set_favorite (EmpathyChatroom *chatroom, + gboolean favorite); G_END_DECLS diff --git a/libempathy/empathy-contact-factory.c b/libempathy/empathy-contact-factory.c deleted file mode 100644 index c35005774..000000000 --- a/libempathy/empathy-contact-factory.c +++ /dev/null @@ -1,187 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2007-2008 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: Xavier Claessens <xclaesse@gmail.com> - */ - -#include <config.h> - -#include "empathy-contact-factory.h" -#include "empathy-utils.h" - -#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContactFactory) -typedef struct { - GHashTable *accounts; -} EmpathyContactFactoryPriv; - -G_DEFINE_TYPE (EmpathyContactFactory, empathy_contact_factory, G_TYPE_OBJECT); - -static EmpathyContactFactory * factory_singleton = NULL; - -EmpathyTpContactFactory * -empathy_contact_factory_get_tp_factory (EmpathyContactFactory *factory, - McAccount *account) -{ - EmpathyContactFactoryPriv *priv = GET_PRIV (factory); - EmpathyTpContactFactory *tp_factory; - - tp_factory = g_hash_table_lookup (priv->accounts, account); - if (!tp_factory) { - tp_factory = empathy_tp_contact_factory_new (account); - g_hash_table_insert (priv->accounts, account, tp_factory); - } - - return g_object_ref (tp_factory); -} - -EmpathyContact * -empathy_contact_factory_get_user (EmpathyContactFactory *factory, - McAccount *account) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_get_user (tp_factory); -} - -EmpathyContact * -empathy_contact_factory_get_from_id (EmpathyContactFactory *factory, - McAccount *account, - const gchar *id) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_get_from_id (tp_factory, id); -} - -EmpathyContact * -empathy_contact_factory_get_from_handle (EmpathyContactFactory *factory, - McAccount *account, - guint handle) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_get_from_handle (tp_factory, handle); -} - -GList * -empathy_contact_factory_get_from_handles (EmpathyContactFactory *factory, - McAccount *account, - const GArray *handles) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_get_from_handles (tp_factory, handles); -} - -void -empathy_contact_factory_set_alias (EmpathyContactFactory *factory, - EmpathyContact *contact, - const gchar *alias) -{ - EmpathyTpContactFactory *tp_factory; - McAccount *account; - - account = empathy_contact_get_account (contact); - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_set_alias (tp_factory, contact, alias); -} - -void -empathy_contact_factory_set_avatar (EmpathyContactFactory *factory, - McAccount *account, - const gchar *data, - gsize size, - const gchar *mime_type) -{ - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (factory, account); - - return empathy_tp_contact_factory_set_avatar (tp_factory, - data, size, mime_type); -} - -static void -contact_factory_finalize (GObject *object) -{ - EmpathyContactFactoryPriv *priv = GET_PRIV (object); - - g_hash_table_destroy (priv->accounts); - - G_OBJECT_CLASS (empathy_contact_factory_parent_class)->finalize (object); -} - -static GObject * -contact_factory_constructor (GType type, - guint n_props, - GObjectConstructParam *props) -{ - GObject *retval; - - if (factory_singleton) { - retval = g_object_ref (factory_singleton); - } else { - retval = G_OBJECT_CLASS (empathy_contact_factory_parent_class)->constructor - (type, n_props, props); - - factory_singleton = EMPATHY_CONTACT_FACTORY (retval); - g_object_add_weak_pointer (retval, (gpointer) &factory_singleton); - } - - return retval; -} - -static void -empathy_contact_factory_class_init (EmpathyContactFactoryClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = contact_factory_finalize; - object_class->constructor = contact_factory_constructor; - - g_type_class_add_private (object_class, sizeof (EmpathyContactFactoryPriv)); -} - -static void -empathy_contact_factory_init (EmpathyContactFactory *factory) -{ - EmpathyContactFactoryPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (factory, - EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactoryPriv); - - factory->priv = priv; - priv->accounts = g_hash_table_new_full (empathy_account_hash, - empathy_account_equal, - g_object_unref, - g_object_unref); -} - -EmpathyContactFactory * -empathy_contact_factory_dup_singleton (void) -{ - return g_object_new (EMPATHY_TYPE_CONTACT_FACTORY, NULL); -} - diff --git a/libempathy/empathy-contact-factory.h b/libempathy/empathy-contact-factory.h deleted file mode 100644 index 16df02bcd..000000000 --- a/libempathy/empathy-contact-factory.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2007-2008 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: Xavier Claessens <xclaesse@gmail.com> - */ - -#ifndef __EMPATHY_CONTACT_FACTORY_H__ -#define __EMPATHY_CONTACT_FACTORY_H__ - -#include <glib.h> - -#include <libmissioncontrol/mc-account.h> - -#include "empathy-contact.h" -#include "empathy-tp-contact-factory.h" - -G_BEGIN_DECLS - -#define EMPATHY_TYPE_CONTACT_FACTORY (empathy_contact_factory_get_type ()) -#define EMPATHY_CONTACT_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactory)) -#define EMPATHY_CONTACT_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactoryClass)) -#define EMPATHY_IS_CONTACT_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_CONTACT_FACTORY)) -#define EMPATHY_IS_CONTACT_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_CONTACT_FACTORY)) -#define EMPATHY_CONTACT_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactoryClass)) - -typedef struct _EmpathyContactFactory EmpathyContactFactory; -typedef struct _EmpathyContactFactoryClass EmpathyContactFactoryClass; - -struct _EmpathyContactFactory { - GObject parent; - gpointer priv; -}; - -struct _EmpathyContactFactoryClass { - GObjectClass parent_class; -}; - -GType empathy_contact_factory_get_type (void) G_GNUC_CONST; -EmpathyContactFactory *empathy_contact_factory_dup_singleton (void); -EmpathyTpContactFactory *empathy_contact_factory_get_tp_factory (EmpathyContactFactory *factory, - McAccount *account); -EmpathyContact * empathy_contact_factory_get_user (EmpathyContactFactory *factory, - McAccount *account); -EmpathyContact * empathy_contact_factory_get_from_id (EmpathyContactFactory *factory, - McAccount *account, - const gchar *id); -EmpathyContact * empathy_contact_factory_get_from_handle (EmpathyContactFactory *factory, - McAccount *account, - guint handle); -GList * empathy_contact_factory_get_from_handles (EmpathyContactFactory *factory, - McAccount *account, - const GArray *handles); -void empathy_contact_factory_set_alias (EmpathyContactFactory *factory, - EmpathyContact *contact, - const gchar *alias); -void empathy_contact_factory_set_avatar (EmpathyContactFactory *factory, - McAccount *account, - const gchar *data, - gsize size, - const gchar *mime_type); - -G_END_DECLS - -#endif /* __EMPATHY_CONTACT_FACTORY_H__ */ diff --git a/libempathy/empathy-contact-manager.c b/libempathy/empathy-contact-manager.c index 409f41c44..66c4514af 100644 --- a/libempathy/empathy-contact-manager.c +++ b/libempathy/empathy-contact-manager.c @@ -86,9 +86,6 @@ contact_manager_groups_changed_cb (EmpathyTpContactList *list, contact, group, is_member); } -static void contact_manager_destroy_cb (EmpathyTpContactList *list, - EmpathyContactManager *manager); - static void contact_manager_disconnect_foreach (gpointer key, gpointer value, @@ -107,75 +104,60 @@ contact_manager_disconnect_foreach (gpointer key, g_signal_handlers_disconnect_by_func (list, contact_manager_groups_changed_cb, manager); - g_signal_handlers_disconnect_by_func (list, - contact_manager_destroy_cb, - manager); } static void -contact_manager_destroy_cb (EmpathyTpContactList *list, - EmpathyContactManager *manager) +contact_manager_invalidated_cb (TpProxy *connection, + guint domain, + gint code, + gchar *message, + EmpathyContactManager *manager) { EmpathyContactManagerPriv *priv = GET_PRIV (manager); - McAccount *account; + EmpathyTpContactList *list; - account = empathy_tp_contact_list_get_account (list); + DEBUG ("Removing connection: %s (%s)", + tp_proxy_get_object_path (TP_PROXY (connection)), + message); - DEBUG ("Removing account: %s", mc_account_get_display_name (account)); - - contact_manager_disconnect_foreach (account, list, manager); - g_hash_table_remove (priv->lists, account); + list = g_hash_table_lookup (priv->lists, connection); + if (list) { + empathy_tp_contact_list_remove_all (list); + g_hash_table_remove (priv->lists, connection); + } } static void -contact_manager_add_account (EmpathyContactManager *manager, - McAccount *account) +contact_manager_new_connection_cb (EmpathyAccountManager *account_manager, + TpConnection *connection, + EmpathyContactManager *self) { - EmpathyContactManagerPriv *priv = GET_PRIV (manager); + EmpathyContactManagerPriv *priv = GET_PRIV (self); EmpathyTpContactList *list; - if (g_hash_table_lookup (priv->lists, account)) { + if (g_hash_table_lookup (priv->lists, connection)) { return; } - DEBUG ("Adding new account: %s", mc_account_get_display_name (account)); - - list = empathy_tp_contact_list_new (account); - if (!list) { - return; - } + DEBUG ("Adding new connection: %s", + tp_proxy_get_object_path (TP_PROXY (connection))); - g_hash_table_insert (priv->lists, g_object_ref (account), list); + list = empathy_tp_contact_list_new (connection); + g_hash_table_insert (priv->lists, g_object_ref (connection), list); + g_signal_connect (connection, "invalidated", + G_CALLBACK (contact_manager_invalidated_cb), + self); /* Connect signals */ g_signal_connect (list, "members-changed", G_CALLBACK (contact_manager_members_changed_cb), - manager); + self); g_signal_connect (list, "pendings-changed", G_CALLBACK (contact_manager_pendings_changed_cb), - manager); + self); g_signal_connect (list, "groups-changed", G_CALLBACK (contact_manager_groups_changed_cb), - manager); - g_signal_connect (list, "destroy", - G_CALLBACK (contact_manager_destroy_cb), - manager); -} - -static void -contact_manager_connection_changed_cb (EmpathyAccountManager *account_manager, - McAccount *account, - TpConnectionStatusReason reason, - TpConnectionStatus current, - TpConnectionStatus previous, - EmpathyContactManager *manager) -{ - if (current != TP_CONNECTION_STATUS_CONNECTED) { - /* We only care about newly connected accounts */ - return; - } - - contact_manager_add_account (manager, account); + self); } static void @@ -189,7 +171,7 @@ contact_manager_finalize (GObject *object) g_hash_table_destroy (priv->lists); g_signal_handlers_disconnect_by_func (priv->account_manager, - contact_manager_connection_changed_cb, + contact_manager_new_connection_cb, object); g_object_unref (priv->account_manager); @@ -232,34 +214,30 @@ empathy_contact_manager_class_init (EmpathyContactManagerClass *klass) static void empathy_contact_manager_init (EmpathyContactManager *manager) { - GSList *accounts, *l; - MissionControl *mc; + GList *connections, *l; EmpathyContactManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, EMPATHY_TYPE_CONTACT_MANAGER, EmpathyContactManagerPriv); manager->priv = priv; - priv->lists = g_hash_table_new_full (empathy_account_hash, - empathy_account_equal, + priv->lists = g_hash_table_new_full (empathy_proxy_hash, + empathy_proxy_equal, (GDestroyNotify) g_object_unref, (GDestroyNotify) g_object_unref); priv->account_manager = empathy_account_manager_dup_singleton (); priv->contact_monitor = NULL; - g_signal_connect (priv->account_manager, - "account-connection-changed", - G_CALLBACK (contact_manager_connection_changed_cb), manager); - - mc = empathy_mission_control_dup_singleton (); + g_signal_connect (priv->account_manager, "new-connection", + G_CALLBACK (contact_manager_new_connection_cb), + manager); /* Get ContactList for existing connections */ - accounts = mission_control_get_online_connections (mc, NULL); - for (l = accounts; l; l = l->next) { - contact_manager_add_account (manager, l->data); + connections = empathy_account_manager_dup_connections (priv->account_manager); + for (l = connections; l; l = l->next) { + contact_manager_new_connection_cb (priv->account_manager, + l->data, manager); g_object_unref (l->data); } - - g_slist_free (accounts); - g_object_unref (mc); + g_list_free (connections); } EmpathyContactManager * @@ -270,14 +248,14 @@ empathy_contact_manager_dup_singleton (void) EmpathyTpContactList * empathy_contact_manager_get_list (EmpathyContactManager *manager, - McAccount *account) + TpConnection *connection) { EmpathyContactManagerPriv *priv = GET_PRIV (manager); g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL); - return g_hash_table_lookup (priv->lists, account); + return g_hash_table_lookup (priv->lists, connection); } static void @@ -287,12 +265,12 @@ contact_manager_add (EmpathyContactList *manager, { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { empathy_contact_list_add (list, contact, message); @@ -301,17 +279,17 @@ contact_manager_add (EmpathyContactList *manager, static void contact_manager_remove (EmpathyContactList *manager, - EmpathyContact *contact, + EmpathyContact *contact, const gchar *message) { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { empathy_contact_list_remove (list, contact, message); @@ -319,7 +297,7 @@ contact_manager_remove (EmpathyContactList *manager, } static void -contact_manager_get_members_foreach (McAccount *account, +contact_manager_get_members_foreach (TpConnection *connection, EmpathyTpContactList *list, GList **contacts) { @@ -357,7 +335,7 @@ contact_manager_get_monitor (EmpathyContactList *manager) } static void -contact_manager_get_pendings_foreach (McAccount *account, +contact_manager_get_pendings_foreach (TpConnection *connection, EmpathyTpContactList *list, GList **contacts) { @@ -383,7 +361,7 @@ contact_manager_get_pendings (EmpathyContactList *manager) } static void -contact_manager_get_all_groups_foreach (McAccount *account, +contact_manager_get_all_groups_foreach (TpConnection *connection, EmpathyTpContactList *list, GList **all_groups) { @@ -424,12 +402,12 @@ contact_manager_get_groups (EmpathyContactList *manager, { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { return empathy_contact_list_get_groups (list, contact); @@ -445,12 +423,12 @@ contact_manager_add_to_group (EmpathyContactList *manager, { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { empathy_contact_list_add_to_group (list, contact, group); @@ -464,12 +442,12 @@ contact_manager_remove_from_group (EmpathyContactList *manager, { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyContactList *list; - McAccount *account; + TpConnection *connection; g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager)); - account = empathy_contact_get_account (contact); - list = g_hash_table_lookup (priv->lists, account); + connection = empathy_contact_get_connection (contact); + list = g_hash_table_lookup (priv->lists, connection); if (list) { empathy_contact_list_remove_from_group (list, contact, group); @@ -482,7 +460,7 @@ typedef struct { } RenameGroupData; static void -contact_manager_rename_group_foreach (McAccount *account, +contact_manager_rename_group_foreach (TpConnection *connection, EmpathyTpContactList *list, RenameGroupData *data) { @@ -508,7 +486,7 @@ contact_manager_rename_group (EmpathyContactList *manager, &data); } -static void contact_manager_remove_group_foreach (McAccount *account, +static void contact_manager_remove_group_foreach (TpConnection *connection, EmpathyTpContactList *list, const gchar *group) { @@ -547,14 +525,14 @@ contact_manager_iface_init (EmpathyContactListIface *iface) gboolean empathy_contact_manager_can_add (EmpathyContactManager *manager, - McAccount *account) + TpConnection *connection) { EmpathyContactManagerPriv *priv = GET_PRIV (manager); EmpathyTpContactList *list; g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), FALSE); - list = g_hash_table_lookup (priv->lists, account); + list = g_hash_table_lookup (priv->lists, connection); if (list == NULL) return FALSE; diff --git a/libempathy/empathy-contact-manager.h b/libempathy/empathy-contact-manager.h index 57e8764e4..fbe9e2df0 100644 --- a/libempathy/empathy-contact-manager.h +++ b/libempathy/empathy-contact-manager.h @@ -24,8 +24,6 @@ #include <glib.h> -#include <libmissioncontrol/mc-account.h> - #include "empathy-contact.h" #include "empathy-tp-contact-list.h" #include "empathy-contact-list.h" @@ -54,9 +52,9 @@ struct _EmpathyContactManagerClass { GType empathy_contact_manager_get_type (void) G_GNUC_CONST; EmpathyContactManager *empathy_contact_manager_dup_singleton (void); EmpathyTpContactList * empathy_contact_manager_get_list (EmpathyContactManager *manager, - McAccount *account); + TpConnection *connection); gboolean empathy_contact_manager_can_add (EmpathyContactManager *manager, - McAccount *account); + TpConnection *connection); G_END_DECLS diff --git a/libempathy/empathy-contact.c b/libempathy/empathy-contact.c index 1cac48513..fe8cf8234 100644 --- a/libempathy/empathy-contact.c +++ b/libempathy/empathy-contact.c @@ -1,27 +1,22 @@ /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ /* - * Copyright (C) 2004 Imendio AB - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. + * This 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 program is distributed in the hope that it will be useful, + * 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 - * General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * 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: Mikael Hallendal <micke@imendio.com> - * Martyn Russell <martyn@imendio.com> - * Xavier Claessens <xclaesse@gmail.com> - * Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * Authors: Xavier Claessens <xclaesse@gmail.com> */ #include "config.h" @@ -34,7 +29,7 @@ #include <libmissioncontrol/mc-enum-types.h> #include "empathy-contact.h" -#include "empathy-contact-factory.h" +#include "empathy-account-manager.h" #include "empathy-utils.h" #include "empathy-enum-types.h" #include "empathy-marshal.h" @@ -44,29 +39,19 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContact) typedef struct { - EmpathyContactFactory *factory; + TpContact *tp_contact; + McAccount *account; gchar *id; gchar *name; EmpathyAvatar *avatar; - McAccount *account; McPresence presence; gchar *presence_message; guint handle; EmpathyCapabilities capabilities; gboolean is_user; guint hash; - EmpathyContactReady ready; - GList *ready_callbacks; } EmpathyContactPriv; -typedef struct { - EmpathyContactReady ready; - EmpathyContactReadyCb *callback; - gpointer user_data; - GDestroyNotify destroy; - GObject *weak_object; -} ReadyCbData; - static void contact_finalize (GObject *object); static void contact_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec); @@ -78,16 +63,16 @@ G_DEFINE_TYPE (EmpathyContact, empathy_contact, G_TYPE_OBJECT); enum { PROP_0, + PROP_TP_CONTACT, + PROP_ACCOUNT, PROP_ID, PROP_NAME, PROP_AVATAR, - PROP_ACCOUNT, PROP_PRESENCE, PROP_PRESENCE_MESSAGE, PROP_HANDLE, PROP_CAPABILITIES, PROP_IS_USER, - PROP_READY }; enum { @@ -98,18 +83,48 @@ enum { static guint signals[LAST_SIGNAL]; static void +tp_contact_notify_cb (TpContact *tp_contact, + GParamSpec *param, + GObject *contact) +{ + EmpathyContactPriv *priv = GET_PRIV (contact); + + /* Forward property notifications */ + if (!tp_strdiff (param->name, "alias")) + g_object_notify (contact, "name"); + else if (!tp_strdiff (param->name, "presence-type")) { + McPresence presence; + + presence = empathy_contact_get_presence (EMPATHY_CONTACT (contact)); + g_signal_emit (contact, signals[PRESENCE_CHANGED], 0, presence, priv->presence); + priv->presence = presence; + g_object_notify (contact, "presence"); + } + else if (!tp_strdiff (param->name, "presence-message")) + g_object_notify (contact, "presence-message"); + else if (!tp_strdiff (param->name, "identifier")) + g_object_notify (contact, "id"); + else if (!tp_strdiff (param->name, "handle")) + g_object_notify (contact, "handle"); +} + +static void contact_dispose (GObject *object) { EmpathyContactPriv *priv = GET_PRIV (object); + if (priv->tp_contact) + { + g_signal_handlers_disconnect_by_func (priv->tp_contact, + tp_contact_notify_cb, object); + g_object_unref (priv->tp_contact); + } + priv->tp_contact = NULL; + if (priv->account) g_object_unref (priv->account); priv->account = NULL; - if (priv->factory) - g_object_unref (priv->factory); - priv->factory = NULL; - G_OBJECT_CLASS (empathy_contact_parent_class)->dispose (object); } @@ -126,12 +141,28 @@ empathy_contact_class_init (EmpathyContactClass *class) object_class->set_property = contact_set_property; g_object_class_install_property (object_class, + PROP_TP_CONTACT, + g_param_spec_object ("tp-contact", + "TpContact", + "The TpContact associated with the contact", + TP_TYPE_CONTACT, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, + PROP_ACCOUNT, + g_param_spec_object ("account", + "The account", + "The account associated with the contact", + MC_TYPE_ACCOUNT, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_ID, g_param_spec_string ("id", "Contact id", "String identifying contact", NULL, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_NAME, @@ -139,7 +170,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Contact Name", "The name of the contact", NULL, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_AVATAR, @@ -147,15 +178,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Avatar image", "The avatar image", EMPATHY_TYPE_AVATAR, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_ACCOUNT, - g_param_spec_object ("account", - "Contact Account", - "The account associated with the contact", - MC_TYPE_ACCOUNT, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_PRESENCE, @@ -165,7 +188,7 @@ empathy_contact_class_init (EmpathyContactClass *class) MC_PRESENCE_UNSET, LAST_MC_PRESENCE, MC_PRESENCE_UNSET, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_PRESENCE_MESSAGE, @@ -173,7 +196,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Contact presence message", "Presence message of contact", NULL, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_HANDLE, @@ -183,7 +206,7 @@ empathy_contact_class_init (EmpathyContactClass *class) 0, G_MAXUINT, 0, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_CAPABILITIES, @@ -192,7 +215,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Capabilities of the contact", EMPATHY_TYPE_CAPABILITIES, EMPATHY_CAPABILITIES_UNKNOWN, - G_PARAM_CONSTRUCT | G_PARAM_READWRITE)); + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_IS_USER, @@ -200,16 +223,7 @@ empathy_contact_class_init (EmpathyContactClass *class) "Contact is-user", "Is contact the user", FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_READY, - g_param_spec_flags ("ready", - "Contact ready flags", - "Flags for ready properties", - EMPATHY_TYPE_CONTACT_READY, - EMPATHY_CONTACT_READY_NONE, - G_PARAM_READABLE)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); signals[PRESENCE_CHANGED] = g_signal_new ("presence-changed", @@ -232,17 +246,12 @@ empathy_contact_init (EmpathyContact *contact) EMPATHY_TYPE_CONTACT, EmpathyContactPriv); contact->priv = priv; - - /* Keep a ref to the factory to be sure it is not finalized while there is - * still contacts alive. */ - priv->factory = empathy_contact_factory_dup_singleton (); } static void contact_finalize (GObject *object) { EmpathyContactPriv *priv; - GList *l; priv = GET_PRIV (object); @@ -252,18 +261,6 @@ contact_finalize (GObject *object) g_free (priv->id); g_free (priv->presence_message); - for (l = priv->ready_callbacks; l != NULL; l = g_list_next (l)) - { - ReadyCbData *d = (ReadyCbData *)l->data; - - if (d->destroy != NULL) - d->destroy (d->user_data); - g_slice_free (ReadyCbData, d); - } - - g_list_free (priv->ready_callbacks); - priv->ready_callbacks = NULL; - if (priv->avatar) empathy_avatar_unref (priv->avatar); @@ -271,47 +268,61 @@ contact_finalize (GObject *object) } static void +set_tp_contact (EmpathyContact *contact, + TpContact *tp_contact) +{ + EmpathyContactPriv *priv = GET_PRIV (contact); + + if (tp_contact == NULL) + return; + + g_assert (priv->tp_contact == NULL); + priv->tp_contact = g_object_ref (tp_contact); + priv->presence = empathy_contact_get_presence (contact); + + g_signal_connect (priv->tp_contact, "notify", + G_CALLBACK (tp_contact_notify_cb), contact); +} + +static void contact_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { - EmpathyContactPriv *priv; - - priv = GET_PRIV (object); + EmpathyContact *contact = EMPATHY_CONTACT (object); switch (param_id) { + case PROP_TP_CONTACT: + g_value_set_object (value, empathy_contact_get_tp_contact (contact)); + break; + case PROP_ACCOUNT: + g_value_set_object (value, empathy_contact_get_account (contact)); + break; case PROP_ID: - g_value_set_string (value, priv->id); + g_value_set_string (value, empathy_contact_get_id (contact)); break; case PROP_NAME: - g_value_set_string (value, - empathy_contact_get_name (EMPATHY_CONTACT (object))); + g_value_set_string (value, empathy_contact_get_name (contact)); break; case PROP_AVATAR: - g_value_set_boxed (value, priv->avatar); - break; - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); + g_value_set_boxed (value, empathy_contact_get_avatar (contact)); break; case PROP_PRESENCE: - g_value_set_uint (value, priv->presence); + g_value_set_uint (value, empathy_contact_get_presence (contact)); break; case PROP_PRESENCE_MESSAGE: - g_value_set_string (value, priv->presence_message); + g_value_set_string (value, empathy_contact_get_presence_message (contact)); break; case PROP_HANDLE: - g_value_set_uint (value, priv->handle); + g_value_set_uint (value, empathy_contact_get_handle (contact)); break; case PROP_CAPABILITIES: - g_value_set_flags (value, priv->capabilities); + g_value_set_flags (value, empathy_contact_get_capabilities (contact)); break; case PROP_IS_USER: - g_value_set_boolean (value, priv->is_user); - break; - case PROP_READY: - g_value_set_flags (value, priv->ready); + g_value_set_boolean (value, empathy_contact_is_user (contact)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -325,47 +336,41 @@ contact_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - EmpathyContactPriv *priv; - - priv = GET_PRIV (object); + EmpathyContact *contact = EMPATHY_CONTACT (object); + EmpathyContactPriv *priv = GET_PRIV (object); switch (param_id) { + case PROP_TP_CONTACT: + set_tp_contact (contact, g_value_get_object (value)); + break; + case PROP_ACCOUNT: + g_assert (priv->account == NULL); + priv->account = g_value_dup_object (value); + break; case PROP_ID: - empathy_contact_set_id (EMPATHY_CONTACT (object), - g_value_get_string (value)); + empathy_contact_set_id (contact, g_value_get_string (value)); break; case PROP_NAME: - empathy_contact_set_name (EMPATHY_CONTACT (object), - g_value_get_string (value)); + empathy_contact_set_name (contact, g_value_get_string (value)); break; case PROP_AVATAR: - empathy_contact_set_avatar (EMPATHY_CONTACT (object), - g_value_get_boxed (value)); - break; - case PROP_ACCOUNT: - empathy_contact_set_account (EMPATHY_CONTACT (object), - MC_ACCOUNT (g_value_get_object (value))); + empathy_contact_set_avatar (contact, g_value_get_boxed (value)); break; case PROP_PRESENCE: - empathy_contact_set_presence (EMPATHY_CONTACT (object), - g_value_get_uint (value)); + empathy_contact_set_presence (contact, g_value_get_uint (value)); break; case PROP_PRESENCE_MESSAGE: - empathy_contact_set_presence_message (EMPATHY_CONTACT (object), - g_value_get_string (value)); + empathy_contact_set_presence_message (contact, g_value_get_string (value)); break; case PROP_HANDLE: - empathy_contact_set_handle (EMPATHY_CONTACT (object), - g_value_get_uint (value)); + empathy_contact_set_handle (contact, g_value_get_uint (value)); break; case PROP_CAPABILITIES: - empathy_contact_set_capabilities (EMPATHY_CONTACT (object), - g_value_get_flags (value)); + empathy_contact_set_capabilities (contact, g_value_get_flags (value)); break; case PROP_IS_USER: - empathy_contact_set_is_user (EMPATHY_CONTACT (object), - g_value_get_boolean (value)); + empathy_contact_set_is_user (contact, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -373,120 +378,43 @@ contact_set_property (GObject *object, }; } -static gboolean -contact_is_ready (EmpathyContact *contact, EmpathyContactReady ready) -{ - EmpathyContactPriv *priv = GET_PRIV (contact); - - /* When the name is NULL, empathy_contact_get_name() fallback to the id. - * When the caller want to wait the name to be ready, it also want to wait - * the id to be ready in case of fallback. */ - if ((ready & EMPATHY_CONTACT_READY_NAME) && EMP_STR_EMPTY (priv->name)) - ready |= EMPATHY_CONTACT_READY_ID; - - return (priv->ready & ready) == ready; -} - -static void -contact_weak_object_notify (gpointer data, GObject *old_object) -{ - EmpathyContact *contact = EMPATHY_CONTACT (data); - EmpathyContactPriv *priv = GET_PRIV (contact); - - GList *l, *ln; - - for (l = priv->ready_callbacks ; l != NULL ; l = ln ) - { - ReadyCbData *d = (ReadyCbData *)l->data; - ln = g_list_next (l); - - if (d->weak_object == old_object) - { - if (d->destroy != NULL) - d->destroy (d->user_data); - - priv->ready_callbacks = g_list_delete_link (priv->ready_callbacks, - l); - - g_slice_free (ReadyCbData, d); - } - } -} - -static void -contact_call_ready_callback (EmpathyContact *contact, const GError *error, - ReadyCbData *data) -{ - data->callback (contact, error, data->user_data, data->weak_object); - if (data->destroy != NULL) - data->destroy (data->user_data); - - if (data->weak_object) - g_object_weak_unref (data->weak_object, - contact_weak_object_notify, contact); -} - - -static void -contact_set_ready_flag (EmpathyContact *contact, - EmpathyContactReady flag) -{ - EmpathyContactPriv *priv = GET_PRIV (contact); - - if (!(priv->ready & flag)) - { - GList *l, *ln; - - priv->ready |= flag; - g_object_notify (G_OBJECT (contact), "ready"); - - for (l = priv->ready_callbacks ; l != NULL ; l = ln ) - { - ReadyCbData *d = (ReadyCbData *)l->data; - ln = g_list_next (l); - - if (contact_is_ready (contact, d->ready)) - { - contact_call_ready_callback (contact, NULL, d); - priv->ready_callbacks = g_list_delete_link - (priv->ready_callbacks, l); - g_slice_free (ReadyCbData, d); - } - } - } -} - -static void -contact_remove_ready_flag (EmpathyContact *contact, - EmpathyContactReady flag) +EmpathyContact * +empathy_contact_new (TpContact *tp_contact) { - EmpathyContactPriv *priv = GET_PRIV (contact); + g_return_val_if_fail (TP_IS_CONTACT (tp_contact), NULL); - if (priv->ready & flag) - { - priv->ready ^= flag; - g_object_notify (G_OBJECT (contact), "ready"); - } + return g_object_new (EMPATHY_TYPE_CONTACT, + "tp-contact", tp_contact, + NULL); } EmpathyContact * -empathy_contact_new (McAccount *account) +empathy_contact_new_for_log (McAccount *account, + const gchar *id, + const gchar *name, + gboolean is_user) { + g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + g_return_val_if_fail (id != NULL, NULL); + return g_object_new (EMPATHY_TYPE_CONTACT, "account", account, + "id", id, + "name", name, + "is-user", is_user, NULL); } -EmpathyContact * -empathy_contact_new_full (McAccount *account, - const gchar *id, - const gchar *name) +TpContact * +empathy_contact_get_tp_contact (EmpathyContact *contact) { - return g_object_new (EMPATHY_TYPE_CONTACT, - "account", account, - "name", name, - "id", id, - NULL); + EmpathyContactPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); + + priv = GET_PRIV (contact); + + return priv->tp_contact; } const gchar * @@ -498,6 +426,9 @@ empathy_contact_get_id (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return tp_contact_get_identifier (priv->tp_contact); + return priv->id; } @@ -524,7 +455,6 @@ empathy_contact_set_id (EmpathyContact *contact, if (EMP_STR_EMPTY (priv->name)) g_object_notify (G_OBJECT (contact), "name"); } - contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_ID); g_object_unref (contact); } @@ -538,6 +468,9 @@ empathy_contact_get_name (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return tp_contact_get_alias (priv->tp_contact); + if (EMP_STR_EMPTY (priv->name)) return empathy_contact_get_id (contact); @@ -561,7 +494,6 @@ empathy_contact_set_name (EmpathyContact *contact, priv->name = g_strdup (name); g_object_notify (G_OBJECT (contact), "name"); } - contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_NAME); g_object_unref (contact); } @@ -611,28 +543,61 @@ empathy_contact_get_account (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->account == NULL && priv->tp_contact != NULL) + { + EmpathyAccountManager *manager; + TpConnection *connection; + + /* FIXME: This assume the account manager already exists */ + manager = empathy_account_manager_dup_singleton (); + connection = tp_contact_get_connection (priv->tp_contact); + priv->account = empathy_account_manager_get_account (manager, connection); + g_object_ref (priv->account); + g_object_unref (manager); + } + return priv->account; } -void -empathy_contact_set_account (EmpathyContact *contact, - McAccount *account) +TpConnection * +empathy_contact_get_connection (EmpathyContact *contact) { EmpathyContactPriv *priv; - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - g_return_if_fail (MC_IS_ACCOUNT (account)); + g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL); priv = GET_PRIV (contact); - if (account == priv->account) - return; + if (priv->tp_contact != NULL) + return tp_contact_get_connection (priv->tp_contact); - if (priv->account) - g_object_unref (priv->account); - priv->account = g_object_ref (account); + return NULL; +} + +static McPresence +presence_type_to_mc_presence (TpConnectionPresenceType type) +{ + switch (type) + { + case TP_CONNECTION_PRESENCE_TYPE_UNSET: + case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN: + case TP_CONNECTION_PRESENCE_TYPE_ERROR: + return MC_PRESENCE_UNSET; + case TP_CONNECTION_PRESENCE_TYPE_OFFLINE: + return MC_PRESENCE_OFFLINE; + case TP_CONNECTION_PRESENCE_TYPE_AVAILABLE: + return MC_PRESENCE_AVAILABLE; + case TP_CONNECTION_PRESENCE_TYPE_AWAY: + return MC_PRESENCE_AWAY; + case TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY: + return MC_PRESENCE_EXTENDED_AWAY; + case TP_CONNECTION_PRESENCE_TYPE_HIDDEN: + return MC_PRESENCE_HIDDEN; + case TP_CONNECTION_PRESENCE_TYPE_BUSY: + return MC_PRESENCE_DO_NOT_DISTURB; + } - g_object_notify (G_OBJECT (contact), "account"); + return MC_PRESENCE_UNSET; } McPresence @@ -644,6 +609,10 @@ empathy_contact_get_presence (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return presence_type_to_mc_presence (tp_contact_get_presence_type ( + priv->tp_contact)); + return priv->presence; } @@ -678,6 +647,9 @@ empathy_contact_get_presence_message (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return tp_contact_get_presence_message (priv->tp_contact); + return priv->presence_message; } @@ -707,6 +679,9 @@ empathy_contact_get_handle (EmpathyContact *contact) priv = GET_PRIV (contact); + if (priv->tp_contact != NULL) + return tp_contact_get_handle (priv->tp_contact); + return priv->handle; } @@ -726,12 +701,6 @@ empathy_contact_set_handle (EmpathyContact *contact, priv->handle = handle; g_object_notify (G_OBJECT (contact), "handle"); } - - if (handle != 0) - contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_HANDLE); - else - contact_remove_ready_flag (contact, EMPATHY_CONTACT_READY_HANDLE); - g_object_unref (contact); } @@ -798,28 +767,24 @@ empathy_contact_set_is_user (EmpathyContact *contact, gboolean empathy_contact_is_online (EmpathyContact *contact) { - EmpathyContactPriv *priv; - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); - priv = GET_PRIV (contact); - - return (priv->presence > MC_PRESENCE_OFFLINE); + return (empathy_contact_get_presence (contact) > MC_PRESENCE_OFFLINE); } const gchar * empathy_contact_get_status (EmpathyContact *contact) { - EmpathyContactPriv *priv; + const gchar *message; g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), ""); - priv = GET_PRIV (contact); - - if (priv->presence_message) - return priv->presence_message; + message = empathy_contact_get_presence_message (contact); + if (!EMP_STR_EMPTY (message)) + return message; - return empathy_presence_get_default_message (priv->presence); + return empathy_presence_get_default_message ( + empathy_contact_get_presence (contact)); } gboolean @@ -847,112 +812,12 @@ empathy_contact_can_send_files (EmpathyContact *contact) return priv->capabilities & EMPATHY_CAPABILITIES_FT; } -EmpathyContactReady -empathy_contact_get_ready (EmpathyContact *contact) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); - - priv = GET_PRIV (contact); - - return priv->ready; -} - -gboolean -empathy_contact_equal (gconstpointer v1, - gconstpointer v2) -{ - McAccount *account_a; - McAccount *account_b; - const gchar *id_a; - const gchar *id_b; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (v1), FALSE); - g_return_val_if_fail (EMPATHY_IS_CONTACT (v2), FALSE); - - account_a = empathy_contact_get_account (EMPATHY_CONTACT (v1)); - account_b = empathy_contact_get_account (EMPATHY_CONTACT (v2)); - - id_a = empathy_contact_get_id (EMPATHY_CONTACT (v1)); - id_b = empathy_contact_get_id (EMPATHY_CONTACT (v2)); - - return empathy_account_equal (account_a, account_b) && - !tp_strdiff (id_a, id_b); -} - -guint -empathy_contact_hash (gconstpointer key) -{ - EmpathyContactPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_CONTACT (key), +1); - - priv = GET_PRIV (EMPATHY_CONTACT (key)); - - if (priv->hash == 0) - { - priv->hash = empathy_account_hash (priv->account) ^ - g_str_hash (priv->id); - } - - return priv->hash; -} - -void empathy_contact_call_when_ready (EmpathyContact *contact, - EmpathyContactReady ready, EmpathyContactReadyCb *callback, - gpointer user_data, GDestroyNotify destroy, GObject *weak_object) -{ - EmpathyContactPriv *priv = GET_PRIV (contact); - - g_return_if_fail (contact != NULL); - g_return_if_fail (callback != NULL); - - if (contact_is_ready (contact, ready)) - { - callback (contact, NULL, user_data, weak_object); - if (destroy != NULL) - destroy (user_data); - } - else - { - ReadyCbData *d = g_slice_new0 (ReadyCbData); - d->ready = ready; - d->callback = callback; - d->user_data = user_data; - d->destroy = destroy; - d->weak_object = weak_object; - - if (weak_object != NULL) - g_object_weak_ref (weak_object, contact_weak_object_notify, contact); - - priv->ready_callbacks = g_list_prepend (priv->ready_callbacks, d); - } -} - -static gboolean -contact_is_ready_func (GObject *contact, - gpointer user_data) -{ - return contact_is_ready (EMPATHY_CONTACT (contact), - GPOINTER_TO_UINT (user_data)); -} - -void -empathy_contact_run_until_ready (EmpathyContact *contact, - EmpathyContactReady ready, - GMainLoop **loop) -{ - empathy_run_until_ready_full (contact, "notify::ready", - contact_is_ready_func, GUINT_TO_POINTER (ready), - loop); -} - static gchar * contact_get_avatar_filename (EmpathyContact *contact, const gchar *token) { EmpathyContactPriv *priv = GET_PRIV (contact); + McAccount *account; gchar *avatar_path; gchar *avatar_file; gchar *token_escaped; @@ -963,11 +828,13 @@ contact_get_avatar_filename (EmpathyContact *contact, contact_escaped = tp_escape_as_identifier (priv->id); token_escaped = tp_escape_as_identifier (token); + account = empathy_contact_get_account (contact); + /* FIXME: Do not use the account, but proto/cm instead */ avatar_path = g_build_filename (g_get_user_cache_dir (), PACKAGE_NAME, "avatars", - mc_account_get_unique_name (priv->account), + mc_account_get_unique_name (account), contact_escaped, NULL); g_mkdir_with_parents (avatar_path, 0700); diff --git a/libempathy/empathy-contact.h b/libempathy/empathy-contact.h index 52c969f61..c10561d0f 100644 --- a/libempathy/empathy-contact.h +++ b/libempathy/empathy-contact.h @@ -1,26 +1,22 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2004 Imendio AB - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. + * This 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 program is distributed in the hope that it will be useful, + * 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 - * General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * 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: Mikael Hallendal <micke@imendio.com> - * Martyn Russell <martyn@imendio.com> - * Xavier Claessens <xclaesse@gmail.com> + * Authors: Xavier Claessens <xclaesse@gmail.com> */ #ifndef __EMPATHY_CONTACT_H__ @@ -28,8 +24,8 @@ #include <glib-object.h> +#include <telepathy-glib/contact.h> #include <libmissioncontrol/mc-account.h> -#include <libmissioncontrol/mission-control.h> G_BEGIN_DECLS @@ -70,18 +66,11 @@ typedef enum { EMPATHY_CAPABILITIES_UNKNOWN = 1 << 7 } EmpathyCapabilities; -typedef enum { - EMPATHY_CONTACT_READY_NONE = 0, - EMPATHY_CONTACT_READY_ID = 1 << 0, - EMPATHY_CONTACT_READY_HANDLE = 1 << 1, - EMPATHY_CONTACT_READY_NAME = 1 << 2, - EMPATHY_CONTACT_READY_ALL = (1 << 3) - 1, -} EmpathyContactReady; - GType empathy_contact_get_type (void) G_GNUC_CONST; -EmpathyContact * empathy_contact_new (McAccount *account); -EmpathyContact * empathy_contact_new_full (McAccount *account, const gchar *id, - const gchar *name); +EmpathyContact * empathy_contact_new (TpContact *tp_contact); +EmpathyContact * empathy_contact_new_for_log (McAccount *account, + const gchar *id, const gchar *name, gboolean is_user); +TpContact * empathy_contact_get_tp_contact (EmpathyContact *contact); const gchar * empathy_contact_get_id (EmpathyContact *contact); void empathy_contact_set_id (EmpathyContact *contact, const gchar *id); const gchar * empathy_contact_get_name (EmpathyContact *contact); @@ -90,7 +79,7 @@ EmpathyAvatar * empathy_contact_get_avatar (EmpathyContact *contact); void empathy_contact_set_avatar (EmpathyContact *contact, EmpathyAvatar *avatar); McAccount * empathy_contact_get_account (EmpathyContact *contact); -void empathy_contact_set_account (EmpathyContact *contact, McAccount *account); +TpConnection * empathy_contact_get_connection (EmpathyContact *contact); McPresence empathy_contact_get_presence (EmpathyContact *contact); void empathy_contact_set_presence (EmpathyContact *contact, McPresence presence); @@ -102,7 +91,6 @@ void empathy_contact_set_handle (EmpathyContact *contact, guint handle); EmpathyCapabilities empathy_contact_get_capabilities (EmpathyContact *contact); void empathy_contact_set_capabilities (EmpathyContact *contact, EmpathyCapabilities capabilities); -EmpathyContactReady empathy_contact_get_ready (EmpathyContact *contact); gboolean empathy_contact_is_user (EmpathyContact *contact); void empathy_contact_set_is_user (EmpathyContact *contact, gboolean is_user); @@ -110,19 +98,8 @@ gboolean empathy_contact_is_online (EmpathyContact *contact); const gchar * empathy_contact_get_status (EmpathyContact *contact); gboolean empathy_contact_can_voip (EmpathyContact *contact); gboolean empathy_contact_can_send_files (EmpathyContact *contact); -gboolean empathy_contact_equal (gconstpointer v1, gconstpointer v2); guint empathy_contact_hash (gconstpointer key); -typedef void (EmpathyContactReadyCb) - (EmpathyContact *contact, const GError *error, gpointer user_data, - GObject *weak_object); -void empathy_contact_call_when_ready (EmpathyContact *contact, - EmpathyContactReady ready, EmpathyContactReadyCb *callback, gpointer - user_data, GDestroyNotify destroy, GObject *weak_object); - -void empathy_contact_run_until_ready (EmpathyContact *contact, - EmpathyContactReady ready, GMainLoop **loop); - void empathy_contact_load_avatar_data (EmpathyContact *contact, const guchar *data, const gsize len, const gchar *format, const gchar *token); diff --git a/libempathy/empathy-dispatch-operation.c b/libempathy/empathy-dispatch-operation.c index 1786e4169..cfe111181 100644 --- a/libempathy/empathy-dispatch-operation.c +++ b/libempathy/empathy-dispatch-operation.c @@ -24,6 +24,7 @@ #include "empathy-dispatch-operation.h" #include <libempathy/empathy-enum-types.h> +#include <libempathy/empathy-tp-contact-factory.h> #include <libempathy/empathy-tp-chat.h> #include <libempathy/empathy-tp-call.h> #include <libempathy/empathy-tp-file.h> @@ -173,10 +174,37 @@ empathy_dispatch_operation_invalidated (TpProxy *proxy, guint domain, } static void +dispatcher_operation_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *self) +{ + EmpathyDispatchOperationPriv *priv = GET_PRIV (self); + + if (error) + { + /* FIXME: We should cancel the operation */ + DEBUG ("Error: %s", error->message); + return; + } + + if (priv->contact != NULL) + g_object_unref (priv->contact); + priv->contact = g_object_ref (contact); + g_object_notify (G_OBJECT (self), "contact"); + + tp_channel_call_when_ready (priv->channel, + empathy_dispatch_operation_channel_ready_cb, self); +} + +static void empathy_dispatch_operation_constructed (GObject *object) { EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object); EmpathyDispatchOperationPriv *priv = GET_PRIV (self); + TpHandle handle; + TpHandleType handle_type; empathy_dispatch_operation_set_status (self, EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING); @@ -185,6 +213,19 @@ empathy_dispatch_operation_constructed (GObject *object) g_signal_connect (priv->channel, "invalidated", G_CALLBACK (empathy_dispatch_operation_invalidated), self); + handle = tp_channel_get_handle (priv->channel, &handle_type); + + if (handle_type == TP_CONN_HANDLE_TYPE_CONTACT && priv->contact == NULL) + { + EmpathyTpContactFactory *factory; + + factory = empathy_tp_contact_factory_dup_singleton (priv->connection); + empathy_tp_contact_factory_get_from_handle (factory, handle, + dispatcher_operation_got_contact_cb, NULL, NULL, object); + g_object_unref (factory); + return; + } + tp_channel_call_when_ready (priv->channel, empathy_dispatch_operation_channel_ready_cb, self); } @@ -365,6 +406,23 @@ empathy_dispatcher_operation_tp_chat_ready_cb (GObject *object, } static void +empathy_dispatcher_operation_tp_file_ready_cb (GObject *object, + GParamSpec *spec, gpointer user_data) +{ + EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data); + EmpathyDispatchOperationPriv *priv = GET_PRIV (self); + + if (!empathy_tp_file_is_ready (EMPATHY_TP_FILE (priv->channel_wrapper))) + return; + + g_signal_handler_disconnect (priv->channel_wrapper, priv->ready_handler); + priv->ready_handler = 0; + + empathy_dispatch_operation_set_status (self, + EMPATHY_DISPATCHER_OPERATION_STATE_PENDING); +} + +static void empathy_dispatch_operation_channel_ready_cb (TpChannel *channel, const GError *error, gpointer user_data) { @@ -395,18 +453,23 @@ empathy_dispatch_operation_channel_ready_cb (TpChannel *channel, G_CALLBACK (empathy_dispatcher_operation_tp_chat_ready_cb), self); return; } - } else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA) { - EmpathyTpCall *call = empathy_tp_call_new (channel); - priv->channel_wrapper = G_OBJECT (call); - + EmpathyTpCall *call = empathy_tp_call_new (channel); + priv->channel_wrapper = G_OBJECT (call); } else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER) { - EmpathyTpFile *file = empathy_tp_file_new (channel); - priv->channel_wrapper = G_OBJECT (file); + EmpathyTpFile *file = empathy_tp_file_new (channel); + priv->channel_wrapper = G_OBJECT (file); + + if (!empathy_tp_file_is_ready (file)) + { + priv->ready_handler = g_signal_connect (file, "notify::ready", + G_CALLBACK (empathy_dispatcher_operation_tp_file_ready_cb), self); + return; + } } ready: @@ -524,7 +587,7 @@ empathy_dispatch_operation_get_tp_connection ( priv = GET_PRIV (operation); - return g_object_ref (priv->connection); + return priv->connection; } TpChannel * diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c index 12c7da967..c8a0f9e60 100644 --- a/libempathy/empathy-dispatcher.c +++ b/libempathy/empathy-dispatcher.c @@ -31,7 +31,6 @@ #include <telepathy-glib/gtypes.h> #include <libmissioncontrol/mission-control.h> -#include <libmissioncontrol/mc-account.h> #include <extensions/extensions.h> @@ -39,7 +38,7 @@ #include "empathy-utils.h" #include "empathy-tube-handler.h" #include "empathy-account-manager.h" -#include "empathy-contact-factory.h" +#include "empathy-tp-contact-factory.h" #include "empathy-tp-file.h" #include "empathy-chatroom-manager.h" #include "empathy-utils.h" @@ -54,8 +53,6 @@ typedef struct MissionControl *mc; /* connection to connection data mapping */ GHashTable *connections; - /* accounts to connection mapping */ - GHashTable *accounts; gpointer token; GSList *tubes; @@ -102,7 +99,6 @@ typedef struct typedef struct { - McAccount *account; /* ObjectPath => DispatchData.. */ GHashTable *dispatched_channels; /* ObjectPath -> EmpathyDispatchOperations */ @@ -185,10 +181,9 @@ free_dispatcher_request_data (DispatcherRequestData *r) } static ConnectionData * -new_connection_data (McAccount *account) +new_connection_data (void) { ConnectionData *cd = g_slice_new0 (ConnectionData); - cd->account = g_object_ref (account); cd->dispatched_channels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) free_dispatch_data); @@ -206,7 +201,7 @@ static void free_connection_data (ConnectionData *cd) { GList *l; - g_object_unref (cd->account); + g_hash_table_destroy (cd->dispatched_channels); g_hash_table_destroy (cd->dispatching_channels); int i; @@ -233,12 +228,8 @@ dispatcher_connection_invalidated_cb (TpConnection *connection, EmpathyDispatcher *dispatcher) { EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - ConnectionData *cd; DEBUG ("Error: %s", message); - cd = g_hash_table_lookup (priv->connections, connection); - - g_hash_table_remove (priv->accounts, cd->account); g_hash_table_remove (priv->connections, connection); } @@ -362,7 +353,6 @@ dispatch_operation_claimed_cb (EmpathyDispatchOperation *operation, connection = empathy_dispatch_operation_get_tp_connection (operation); cd = g_hash_table_lookup (priv->connections, connection); g_assert (cd != NULL); - g_object_unref (G_OBJECT (connection)); object_path = empathy_dispatch_operation_get_object_path (operation); @@ -406,7 +396,6 @@ dispatch_operation_ready_cb (EmpathyDispatchOperation *operation, connection = empathy_dispatch_operation_get_tp_connection (operation); cd = g_hash_table_lookup (priv->connections, connection); g_assert (cd != NULL); - g_object_unref (G_OBJECT (connection)); g_object_ref (operation); g_object_ref (dispatcher); @@ -511,7 +500,6 @@ dispatcher_connection_new_channel (EmpathyDispatcher *dispatcher, TpChannel *channel; ConnectionData *cd; EmpathyDispatchOperation *operation; - EmpathyContact *contact = NULL; int i; /* Channel types we never want to dispatch because they're either deprecated * or can't sensibly be dispatch (e.g. channels that should always be @@ -575,15 +563,7 @@ dispatcher_connection_new_channel (EmpathyDispatcher *dispatcher, priv->channels = g_list_prepend (priv->channels, channel); - if (handle_type == TP_CONN_HANDLE_TYPE_CONTACT) - { - EmpathyContactFactory *factory = empathy_contact_factory_dup_singleton (); - contact = empathy_contact_factory_get_from_handle (factory, - cd->account, handle); - g_object_unref (factory); - } - - operation = empathy_dispatch_operation_new (connection, channel, contact, + operation = empathy_dispatch_operation_new (connection, channel, NULL, incoming); g_object_unref (channel); @@ -786,21 +766,21 @@ dispatcher_connection_advertise_capabilities_cb (TpConnection *connection, } static void -dispatcher_connection_ready_cb (TpConnection *connection, - const GError *error, - gpointer dispatcher) +dispatcher_new_connection_cb (EmpathyAccountManager *manager, + TpConnection *connection, + EmpathyDispatcher *dispatcher) { + EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); GPtrArray *capabilities; GType cap_type; GValue cap = {0, }; const gchar *remove = NULL; - if (error) - { - dispatcher_connection_invalidated_cb (connection, error->domain, - error->code, error->message, dispatcher); - return; - } + if (g_hash_table_lookup (priv->connections, connection) != NULL) + return; + + g_hash_table_insert (priv->connections, g_object_ref (connection), + new_connection_data ()); g_signal_connect (connection, "invalidated", G_CALLBACK (dispatcher_connection_invalidated_cb), dispatcher); @@ -815,7 +795,7 @@ dispatcher_connection_ready_cb (TpConnection *connection, tp_cli_dbus_properties_call_get_all (connection, -1, TP_IFACE_CONNECTION_INTERFACE_REQUESTS, dispatcher_connection_got_all, - NULL, NULL, dispatcher); + NULL, NULL, G_OBJECT (dispatcher)); } else { @@ -852,44 +832,6 @@ dispatcher_connection_ready_cb (TpConnection *connection, g_ptr_array_free (capabilities, TRUE); } -static void -dispatcher_update_account (EmpathyDispatcher *dispatcher, - McAccount *account) -{ - EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - TpConnection *connection; - - connection = g_hash_table_lookup (priv->accounts, account); - if (connection != NULL) - return; - - connection = mission_control_get_tpconnection (priv->mc, account, NULL); - if (connection == NULL) - return; - - g_hash_table_insert (priv->connections, g_object_ref (connection), - new_connection_data (account)); - - g_hash_table_insert (priv->accounts, g_object_ref (account), - g_object_ref (connection)); - - tp_connection_call_when_ready (connection, dispatcher_connection_ready_cb, - dispatcher); - - g_object_unref (connection); -} - -static void -dispatcher_account_connection_cb (EmpathyAccountManager *manager, - McAccount *account, - TpConnectionStatusReason reason, - TpConnectionStatus status, - TpConnectionStatus previous, - EmpathyDispatcher *dispatcher) -{ - dispatcher_update_account (dispatcher, account); -} - static GObject* dispatcher_constructor (GType type, guint n_construct_params, @@ -922,7 +864,7 @@ dispatcher_finalize (GObject *object) gpointer connection; g_signal_handlers_disconnect_by_func (priv->account_manager, - dispatcher_account_connection_cb, object); + dispatcher_new_connection_cb, object); for (l = priv->channels; l; l = l->next) { @@ -942,7 +884,6 @@ dispatcher_finalize (GObject *object) g_object_unref (priv->account_manager); g_object_unref (priv->mc); - g_hash_table_destroy (priv->accounts); g_hash_table_destroy (priv->connections); } @@ -991,7 +932,7 @@ empathy_dispatcher_class_init (EmpathyDispatcherClass *klass) static void empathy_dispatcher_init (EmpathyDispatcher *dispatcher) { - GList *accounts, *l; + GList *connections, *l; EmpathyDispatcherPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (dispatcher, EMPATHY_TYPE_DISPATCHER, EmpathyDispatcherPriv); @@ -999,27 +940,22 @@ empathy_dispatcher_init (EmpathyDispatcher *dispatcher) priv->mc = empathy_mission_control_dup_singleton (); priv->account_manager = empathy_account_manager_dup_singleton (); - g_signal_connect (priv->account_manager, - "account-connection-changed", - G_CALLBACK (dispatcher_account_connection_cb), + g_signal_connect (priv->account_manager, "new-connection", + G_CALLBACK (dispatcher_new_connection_cb), dispatcher); - priv->accounts = g_hash_table_new_full (empathy_account_hash, - empathy_account_equal, g_object_unref, g_object_unref); - priv->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, (GDestroyNotify) free_connection_data); priv->channels = NULL; - accounts = mc_accounts_list_by_enabled (TRUE); - - for (l = accounts; l; l = l->next) + connections = empathy_account_manager_dup_connections (priv->account_manager); + for (l = connections; l; l = l->next) { - dispatcher_update_account (dispatcher, l->data); + dispatcher_new_connection_cb (priv->account_manager, l->data, dispatcher); g_object_unref (l->data); } - g_list_free (accounts); + g_list_free (connections); } EmpathyDispatcher * @@ -1168,57 +1104,12 @@ dispatcher_request_channel (DispatcherRequestData *request_data) } void -empathy_dispatcher_call_with_contact (EmpathyContact *contact, - EmpathyDispatcherRequestCb *callback, - gpointer user_data) -{ - EmpathyDispatcher *dispatcher = empathy_dispatcher_dup_singleton(); - EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - McAccount *account; - TpConnection *connection; - ConnectionData *cd; - DispatcherRequestData *request_data; - - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - - account = empathy_contact_get_account (contact); - connection = g_hash_table_lookup (priv->accounts, account); - - g_assert (connection != NULL); - cd = g_hash_table_lookup (priv->connections, connection); - request_data = new_dispatcher_request_data (dispatcher, connection, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, TP_HANDLE_TYPE_NONE, 0, NULL, - contact, callback, user_data); - - cd->outstanding_requests = g_list_prepend - (cd->outstanding_requests, request_data); - - dispatcher_request_channel (request_data); - - g_object_unref (dispatcher); -} - -static void -dispatcher_chat_with_contact_cb (EmpathyContact *contact, - const GError *error, - gpointer user_data, - GObject *object) -{ - DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; - - request_data->handle = empathy_contact_get_handle (contact); - - dispatcher_request_channel (request_data); -} - -void empathy_dispatcher_chat_with_contact (EmpathyContact *contact, EmpathyDispatcherRequestCb *callback, gpointer user_data) { EmpathyDispatcher *dispatcher; EmpathyDispatcherPriv *priv; - McAccount *account; TpConnection *connection; ConnectionData *connection_data; DispatcherRequestData *request_data; @@ -1228,46 +1119,75 @@ empathy_dispatcher_chat_with_contact (EmpathyContact *contact, dispatcher = empathy_dispatcher_dup_singleton(); priv = GET_PRIV (dispatcher); - account = empathy_contact_get_account (contact); - connection = g_hash_table_lookup (priv->accounts, account); + connection = empathy_contact_get_connection (contact); connection_data = g_hash_table_lookup (priv->connections, connection); /* The contact handle might not be known yet */ request_data = new_dispatcher_request_data (dispatcher, connection, - TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_CONTACT, 0, NULL, - contact, callback, user_data); + TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_CONTACT, + empathy_contact_get_handle (contact), NULL, contact, callback, user_data); connection_data->outstanding_requests = g_list_prepend (connection_data->outstanding_requests, request_data); - empathy_contact_call_when_ready (contact, - EMPATHY_CONTACT_READY_HANDLE, dispatcher_chat_with_contact_cb, - request_data, NULL, G_OBJECT (dispatcher)); + dispatcher_request_channel (request_data); g_object_unref (dispatcher); } +typedef struct +{ + EmpathyDispatcher *dispatcher; + EmpathyDispatcherRequestCb *callback; + gpointer user_data; +} ChatWithContactIdData; + +static void +dispatcher_chat_with_contact_id_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + ChatWithContactIdData *data = user_data; + + if (error) + { + /* FIXME: Should call data->callback with the error */ + DEBUG ("Error: %s", error->message); + } + else + { + empathy_dispatcher_chat_with_contact (contact, data->callback, data->user_data); + } + + g_object_unref (data->dispatcher); + g_slice_free (ChatWithContactIdData, data); +} + void -empathy_dispatcher_chat_with_contact_id (McAccount *account, +empathy_dispatcher_chat_with_contact_id (TpConnection *connection, const gchar *contact_id, EmpathyDispatcherRequestCb *callback, gpointer user_data) { - EmpathyDispatcher *dispatcher = empathy_dispatcher_dup_singleton (); - EmpathyContactFactory *factory; - EmpathyContact *contact; + EmpathyDispatcher *dispatcher; + EmpathyTpContactFactory *factory; + ChatWithContactIdData *data; - g_return_if_fail (MC_IS_ACCOUNT (account)); + g_return_if_fail (TP_IS_CONNECTION (connection)); g_return_if_fail (!EMP_STR_EMPTY (contact_id)); - factory = empathy_contact_factory_dup_singleton (); - contact = empathy_contact_factory_get_from_id (factory, account, contact_id); - - empathy_dispatcher_chat_with_contact (contact, callback, user_data); + dispatcher = empathy_dispatcher_dup_singleton (); + factory = empathy_tp_contact_factory_dup_singleton (connection); + data = g_slice_new0 (ChatWithContactIdData); + data->dispatcher = dispatcher; + data->callback = callback; + data->user_data = user_data; + empathy_tp_contact_factory_get_from_id (factory, contact_id, + dispatcher_chat_with_contact_id_cb, data, NULL, NULL); - g_object_unref (contact); g_object_unref (factory); - g_object_unref (dispatcher); } static void @@ -1304,7 +1224,7 @@ dispatcher_request_handles_cb (TpConnection *connection, } void -empathy_dispatcher_join_muc (McAccount *account, +empathy_dispatcher_join_muc (TpConnection *connection, const gchar *roomname, EmpathyDispatcherRequestCb *callback, gpointer user_data) @@ -1312,20 +1232,17 @@ empathy_dispatcher_join_muc (McAccount *account, EmpathyDispatcher *dispatcher; EmpathyDispatcherPriv *priv; DispatcherRequestData *request_data; - TpConnection *connection; ConnectionData *connection_data; const gchar *names[] = { roomname, NULL }; - g_return_if_fail (MC_IS_ACCOUNT (account)); + g_return_if_fail (TP_IS_CONNECTION (connection)); g_return_if_fail (!EMP_STR_EMPTY (roomname)); dispatcher = empathy_dispatcher_dup_singleton(); priv = GET_PRIV (dispatcher); - connection = g_hash_table_lookup (priv->accounts, account); connection_data = g_hash_table_lookup (priv->connections, connection); - /* Don't know the room handle yet */ request_data = new_dispatcher_request_data (dispatcher, connection, TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_ROOM, 0, NULL, @@ -1359,7 +1276,7 @@ dispatcher_create_channel_cb (TpConnection *connect, void empathy_dispatcher_create_channel (EmpathyDispatcher *dispatcher, - McAccount *account, + TpConnection *connection, GHashTable *request, EmpathyDispatcherRequestCb *callback, gpointer user_data) @@ -1371,15 +1288,11 @@ empathy_dispatcher_create_channel (EmpathyDispatcher *dispatcher, guint handle_type; guint handle; gboolean valid; - TpConnection *connection; g_return_if_fail (EMPATHY_IS_DISPATCHER (dispatcher)); - g_return_if_fail (MC_IS_ACCOUNT (account)); + g_return_if_fail (TP_IS_CONNECTION (connection)); g_return_if_fail (request != NULL); - connection = g_hash_table_lookup (priv->accounts, account); - g_assert (connection != NULL); - connection_data = g_hash_table_lookup (priv->connections, connection); g_assert (connection_data != NULL); @@ -1405,56 +1318,6 @@ empathy_dispatcher_create_channel (EmpathyDispatcher *dispatcher, G_OBJECT (request_data->dispatcher)); } -static void -dispatcher_create_channel_with_contact_cb (EmpathyContact *contact, - const GError *error, - gpointer user_data, - GObject *object) -{ - DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; - GValue *target_handle; - - g_assert (request_data->request); - - if (error != NULL) - { - dispatcher_request_failed (request_data->dispatcher, - request_data, error); - return; - } - - request_data->handle = empathy_contact_get_handle (contact); - - target_handle = tp_g_value_slice_new (G_TYPE_UINT); - g_value_set_uint (target_handle, request_data->handle); - g_hash_table_insert (request_data->request, - TP_IFACE_CHANNEL ".TargetHandle", target_handle); - - tp_cli_connection_interface_requests_call_create_channel ( - request_data->connection, -1, - request_data->request, dispatcher_create_channel_cb, request_data, NULL, - G_OBJECT (request_data->dispatcher)); -} - -static void -dispatcher_send_file_connection_ready_cb (TpConnection *connection, - const GError *error, - gpointer user_data) -{ - DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; - - if (error != NULL) - { - dispatcher_request_failed (request_data->dispatcher, - request_data, error); - return; - } - - empathy_contact_call_when_ready (request_data->contact, - EMPATHY_CONTACT_READY_HANDLE, dispatcher_create_channel_with_contact_cb, - request_data, NULL, G_OBJECT (request_data->dispatcher)); -} - void empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, const gchar *filename, @@ -1466,8 +1329,7 @@ empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, { EmpathyDispatcher *dispatcher = empathy_dispatcher_dup_singleton(); EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - McAccount *account = empathy_contact_get_account (contact); - TpConnection *connection = g_hash_table_lookup (priv->accounts, account); + TpConnection *connection = empathy_contact_get_connection (contact); ConnectionData *connection_data = g_hash_table_lookup (priv->connections, connection); DispatcherRequestData *request_data; @@ -1489,6 +1351,11 @@ empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT); g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandleType", value); + /* org.freedesktop.Telepathy.Channel.TargetHandle */ + value = tp_g_value_slice_new (G_TYPE_UINT); + g_value_set_uint (value, empathy_contact_get_handle (contact)); + g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandle", value); + /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentType */ value = tp_g_value_slice_new (G_TYPE_STRING); g_value_set_string (value, content_type); @@ -1513,46 +1380,40 @@ empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, g_hash_table_insert (request, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Date", value); - - /* The contact handle might not be known yet */ - request_data = new_dispatcher_request_data (dispatcher, connection, - TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, TP_HANDLE_TYPE_CONTACT, 0, request, - contact, callback, user_data); + request_data = new_dispatcher_request_data (dispatcher, connection, + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, TP_HANDLE_TYPE_CONTACT, + empathy_contact_get_handle (contact), request, contact, callback, + user_data); connection_data->outstanding_requests = g_list_prepend (connection_data->outstanding_requests, request_data); - tp_connection_call_when_ready (connection, - dispatcher_send_file_connection_ready_cb, (gpointer) request_data); + tp_cli_connection_interface_requests_call_create_channel ( + request_data->connection, -1, + request_data->request, dispatcher_create_channel_cb, request_data, NULL, + G_OBJECT (request_data->dispatcher)); g_object_unref (dispatcher); } GStrv empathy_dispatcher_find_channel_class (EmpathyDispatcher *dispatcher, - McAccount *account, + TpConnection *connection, const gchar *channel_type, guint handle_type) { EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); ConnectionData *cd; - TpConnection *connection; int i; GPtrArray *classes; g_return_val_if_fail (channel_type != NULL, NULL); g_return_val_if_fail (handle_type != 0, NULL); - connection = g_hash_table_lookup (priv->accounts, account); - - if (connection == NULL) - return NULL; - cd = g_hash_table_lookup (priv->connections, connection); if (cd == NULL) return NULL; - classes = cd->requestable_channels; if (classes == NULL) return NULL; diff --git a/libempathy/empathy-dispatcher.h b/libempathy/empathy-dispatcher.h index 13ef06afd..fb7c6fe35 100644 --- a/libempathy/empathy-dispatcher.h +++ b/libempathy/empathy-dispatcher.h @@ -62,15 +62,11 @@ typedef void (EmpathyDispatcherRequestCb) ( GType empathy_dispatcher_get_type (void) G_GNUC_CONST; void empathy_dispatcher_create_channel (EmpathyDispatcher *dispatcher, - McAccount *account, GHashTable *request, - EmpathyDispatcherRequestCb *callback, gpointer user_data); - -/* Requesting 1 to 1 stream media channels */ -void empathy_dispatcher_call_with_contact (EmpathyContact *contact, + TpConnection *connection, GHashTable *request, EmpathyDispatcherRequestCb *callback, gpointer user_data); /* Requesting 1 to 1 text channels */ -void empathy_dispatcher_chat_with_contact_id (McAccount *account, +void empathy_dispatcher_chat_with_contact_id (TpConnection *connection, const gchar *contact_id, EmpathyDispatcherRequestCb *callback, gpointer user_data); void empathy_dispatcher_chat_with_contact (EmpathyContact *contact, @@ -83,12 +79,12 @@ void empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, gpointer user_data); /* Request a muc channel */ -void empathy_dispatcher_join_muc (McAccount *account, +void empathy_dispatcher_join_muc (TpConnection *connection, const gchar *roomname, EmpathyDispatcherRequestCb *callback, gpointer user_data); GStrv empathy_dispatcher_find_channel_class (EmpathyDispatcher *dispatcher, - McAccount *account, const gchar *channel_type, guint handle_type); + TpConnection *connection, const gchar *channel_type, guint handle_type); /* Get the dispatcher singleton */ EmpathyDispatcher * empathy_dispatcher_dup_singleton (void); diff --git a/libempathy/empathy-log-store-empathy.c b/libempathy/empathy-log-store-empathy.c index 37a76676f..b74b5e177 100644 --- a/libempathy/empathy-log-store-empathy.c +++ b/libempathy/empathy-log-store-empathy.c @@ -481,8 +481,9 @@ log_store_empathy_get_messages_for_file (EmpathyLogStore *self, t = empathy_time_parse (time); - sender = empathy_contact_new_full (account, sender_id, sender_name); - empathy_contact_set_is_user (sender, is_user); + sender = empathy_contact_new_for_log (account, sender_id, sender_name, + is_user); + if (!EMP_STR_EMPTY (sender_avatar_token)) empathy_contact_load_avatar_cache (sender, sender_avatar_token); diff --git a/libempathy/empathy-tp-call.c b/libempathy/empathy-tp-call.c index 42bf7a063..a5c0003c5 100644 --- a/libempathy/empathy-tp-call.c +++ b/libempathy/empathy-tp-call.c @@ -27,7 +27,7 @@ #include <telepathy-glib/interfaces.h> #include "empathy-tp-call.h" -#include "empathy-contact-factory.h" +#include "empathy-tp-contact-factory.h" #include "empathy-utils.h" #define DEBUG_FLAG EMPATHY_DEBUG_TP @@ -253,22 +253,27 @@ tp_call_request_streams_for_capabilities (EmpathyTpCall *call, g_array_free (stream_types, TRUE); } -static EmpathyContact * -tp_call_dup_contact_from_handle (EmpathyTpCall *call, TpHandle handle) +static void +tp_call_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *call) { EmpathyTpCallPriv *priv = GET_PRIV (call); - EmpathyContactFactory *factory; - McAccount *account; - EmpathyContact *contact; - - factory = empathy_contact_factory_dup_singleton (); - account = empathy_channel_get_account (priv->channel); - contact = empathy_contact_factory_get_from_handle (factory, account, handle); - g_object_unref (factory); - g_object_unref (account); + if (error) + { + DEBUG ("Error: %s", error->message); + return; + } - return contact; + priv->contact = g_object_ref (contact); + priv->is_incoming = TRUE; + priv->status = EMPATHY_TP_CALL_STATUS_PENDING; + g_object_notify (G_OBJECT (call), "is-incoming"); + g_object_notify (G_OBJECT (call), "contact"); + g_object_notify (G_OBJECT (call), "status"); } static void @@ -288,13 +293,15 @@ tp_call_update_status (EmpathyTpCall *call) { if (priv->contact == NULL && iter.element != self_handle) { + EmpathyTpContactFactory *factory; + TpConnection *connection; + /* We found the remote contact */ - priv->contact = tp_call_dup_contact_from_handle (call, iter.element); - priv->is_incoming = TRUE; - priv->status = EMPATHY_TP_CALL_STATUS_PENDING; - g_object_notify (G_OBJECT (call), "is-incoming"); - g_object_notify (G_OBJECT (call), "contact"); - g_object_notify (G_OBJECT (call), "status"); + connection = tp_channel_borrow_connection (priv->channel); + factory = empathy_tp_contact_factory_dup_singleton (connection); + empathy_tp_contact_factory_get_from_handle (factory, iter.element, + tp_call_got_contact_cb, NULL, NULL, G_OBJECT (call)); + g_object_unref (factory); } if (priv->status == EMPATHY_TP_CALL_STATUS_PENDING && @@ -309,20 +316,6 @@ tp_call_update_status (EmpathyTpCall *call) g_object_unref (call); } -static void -tp_call_members_changed_cb (TpChannel *channel, - gchar *message, - GArray *added, - GArray *removed, - GArray *local_pending, - GArray *remote_pending, - guint actor, - guint reason, - EmpathyTpCall *call) -{ - tp_call_update_status (call); -} - void empathy_tp_call_to (EmpathyTpCall *call, EmpathyContact *contact) { @@ -392,8 +385,8 @@ tp_call_constructor (GType type, /* Update status when members changes */ tp_call_update_status (call); - g_signal_connect (priv->channel, "group-members-changed", - G_CALLBACK (tp_call_members_changed_cb), call); + g_signal_connect_swapped (priv->channel, "group-members-changed", + G_CALLBACK (tp_call_update_status), call); return object; } diff --git a/libempathy/empathy-tp-chat.c b/libempathy/empathy-tp-chat.c index 048f5b275..54e08d071 100644 --- a/libempathy/empathy-tp-chat.c +++ b/libempathy/empathy-tp-chat.c @@ -28,8 +28,7 @@ #include <telepathy-glib/util.h> #include "empathy-tp-chat.h" -#include "empathy-tp-group.h" -#include "empathy-contact-factory.h" +#include "empathy-tp-contact-factory.h" #include "empathy-contact-monitor.h" #include "empathy-contact-list.h" #include "empathy-marshal.h" @@ -42,12 +41,11 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpChat) typedef struct { gboolean dispose_has_run; - EmpathyContactFactory *factory; + EmpathyTpContactFactory *factory; EmpathyContactMonitor *contact_monitor; EmpathyContact *user; EmpathyContact *remote_contact; - EmpathyTpGroup *group; - McAccount *account; + GList *members; TpChannel *channel; gboolean listing_pending_messages; /* Queue of messages not signalled yet */ @@ -57,7 +55,6 @@ typedef struct { gboolean had_properties_list; GPtrArray *properties; gboolean ready; - guint members_count; } EmpathyTpChatPriv; typedef struct { @@ -100,13 +97,8 @@ tp_chat_invalidated_cb (TpProxy *proxy, gchar *message, EmpathyTpChat *chat) { - EmpathyTpChatPriv *priv = GET_PRIV (chat); - DEBUG ("Channel invalidated: %s", message); g_signal_emit (chat, signals[DESTROY], 0); - - g_object_unref (priv->channel); - priv->channel = NULL; } static void @@ -121,108 +113,6 @@ tp_chat_async_cb (TpChannel *proxy, } static void -tp_chat_member_added_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - guint handle_type = 0; - - if (priv->channel == NULL) - return; - - priv->members_count++; - g_signal_emit_by_name (chat, "members-changed", - contact, actor, reason, message, - TRUE); - - g_object_get (priv->channel, "handle-type", &handle_type, NULL); - if (handle_type == TP_HANDLE_TYPE_ROOM) { - return; - } - - if (priv->members_count > 2 && priv->remote_contact) { - /* We now have more than 2 members, this is not a p2p chat - * anymore. Remove the remote-contact as it makes no sense, the - * EmpathyContactList interface must be used now. */ - g_object_unref (priv->remote_contact); - priv->remote_contact = NULL; - g_object_notify (G_OBJECT (chat), "remote-contact"); - } - if (priv->members_count <= 2 && !priv->remote_contact && - !empathy_contact_is_user (contact)) { - /* This is a p2p chat, if it's not ourself that means this is - * the remote contact with who we are chatting. This is to - * avoid forcing the usage of the EmpathyContactList interface - * for p2p chats. */ - priv->remote_contact = g_object_ref (contact); - g_object_notify (G_OBJECT (chat), "remote-contact"); - } -} - -static void -tp_chat_member_removed_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - guint handle_type = 0; - - if (priv->channel == NULL) - return; - - priv->members_count--; - g_signal_emit_by_name (chat, "members-changed", - contact, actor, reason, message, - FALSE); - - g_object_get (priv->channel, "handle-type", &handle_type, NULL); - if (handle_type == TP_HANDLE_TYPE_ROOM) { - return; - } - - if (priv->members_count <= 2 && !priv->remote_contact) { - GList *members, *l; - - /* We are not a MUC anymore, get the remote contact back */ - members = empathy_tp_group_get_members (group); - for (l = members; l; l = l->next) { - if (!empathy_contact_is_user (l->data)) { - priv->remote_contact = g_object_ref (l->data); - g_object_notify (G_OBJECT (chat), "remote-contact"); - break; - } - } - g_list_foreach (members, (GFunc) g_object_unref, NULL); - g_list_free (members); - } -} - -static void -tp_chat_local_pending_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - - if (priv->channel == NULL) - return; - - g_signal_emit_by_name (chat, "pendings-changed", - contact, actor, reason, message, - TRUE); -} - -static void tp_chat_add (EmpathyContactList *list, EmpathyContact *contact, const gchar *message) @@ -268,8 +158,9 @@ tp_chat_get_members (EmpathyContactList *list) g_return_val_if_fail (EMPATHY_IS_TP_CHAT (list), NULL); - if (priv->group) { - members = empathy_tp_group_get_members (priv->group); + if (priv->members) { + members = g_list_copy (priv->members); + g_list_foreach (members, (GFunc) g_object_ref, NULL); } else { members = g_list_prepend (members, g_object_ref (priv->user)); members = g_list_prepend (members, g_object_ref (priv->remote_contact)); @@ -294,119 +185,74 @@ tp_chat_get_monitor (EmpathyContactList *list) return priv->contact_monitor; } -static EmpathyMessage * -tp_chat_build_message (EmpathyTpChat *chat, - guint id, - guint type, - guint timestamp, - guint from_handle, - const gchar *message_body) +static void +tp_chat_emit_queued_messages (EmpathyTpChat *chat) { - EmpathyTpChatPriv *priv; + EmpathyTpChatPriv *priv = GET_PRIV (chat); EmpathyMessage *message; - EmpathyContact *sender; - priv = GET_PRIV (chat); - - if (from_handle == 0) { - sender = g_object_ref (priv->user); - } else { - sender = empathy_contact_factory_get_from_handle (priv->factory, - priv->account, - from_handle); - } - - message = empathy_message_new (message_body); - empathy_message_set_tptype (message, type); - empathy_message_set_sender (message, sender); - empathy_message_set_receiver (message, priv->user); - empathy_message_set_timestamp (message, timestamp); - empathy_message_set_id (message, id); - - g_object_unref (sender); - - return message; -} - -static void -tp_chat_sender_ready_notify_cb (EmpathyContact *contact, - GParamSpec *param_spec, - EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyMessage *message; - EmpathyContactReady ready; - EmpathyContact *sender = NULL; - gboolean removed = FALSE; - - /* Emit all messages queued until we find a message with not - * ready sender (in case of a MUC we could have more than one sender). - * When leaving this loop, sender is the first not ready contact queued - * and removed tells if at least one message got removed - * from the queue. */ + /* Check if we can now emit some queued messages */ while ((message = g_queue_peek_head (priv->messages_queue)) != NULL) { - sender = empathy_message_get_sender (message); - ready = empathy_contact_get_ready (sender); - - if ((ready & EMPATHY_CONTACT_READY_NAME) == 0 || - (ready & EMPATHY_CONTACT_READY_ID) == 0) { + if (empathy_message_get_sender (message) == NULL) { break; } DEBUG ("Queued message ready"); - message = g_queue_pop_head (priv->messages_queue); + g_queue_pop_head (priv->messages_queue); g_queue_push_tail (priv->pending_messages_queue, message); g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message); - removed = TRUE; } +} - if (removed) { - /* We removed at least one message from the queue, disconnect - * the ready signal from the previous contact */ - g_signal_handlers_disconnect_by_func (contact, - tp_chat_sender_ready_notify_cb, - chat); - - if (g_queue_get_length (priv->messages_queue) > 0) { - /* We still have queued message, connect the ready - * signal on the new first message sender. */ - g_signal_connect (sender, "notify::ready", - G_CALLBACK (tp_chat_sender_ready_notify_cb), - chat); - } +static void +tp_chat_got_sender_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer message, + GObject *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + + if (error) { + DEBUG ("Error: %s", error->message); + /* Do not block the message queue, just drop this message */ + g_queue_remove (priv->messages_queue, message); + } else { + empathy_message_set_sender (message, contact); } + + tp_chat_emit_queued_messages (EMPATHY_TP_CHAT (chat)); } static void -tp_chat_emit_or_queue_message (EmpathyTpChat *chat, - EmpathyMessage *message) +tp_chat_build_message (EmpathyTpChat *chat, + guint id, + guint type, + guint timestamp, + guint from_handle, + const gchar *message_body) { - EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyContact *sender; - EmpathyContactReady ready; + EmpathyTpChatPriv *priv; + EmpathyMessage *message; - if (g_queue_get_length (priv->messages_queue) > 0) { - DEBUG ("Message queue not empty"); - g_queue_push_tail (priv->messages_queue, g_object_ref (message)); - return; - } + priv = GET_PRIV (chat); + message = empathy_message_new (message_body); + empathy_message_set_tptype (message, type); + empathy_message_set_receiver (message, priv->user); + empathy_message_set_timestamp (message, timestamp); + empathy_message_set_id (message, id); + g_queue_push_tail (priv->messages_queue, message); - sender = empathy_message_get_sender (message); - ready = empathy_contact_get_ready (sender); - if ((ready & EMPATHY_CONTACT_READY_NAME) && - (ready & EMPATHY_CONTACT_READY_ID)) { - DEBUG ("Message queue empty and sender ready"); - g_queue_push_tail (priv->pending_messages_queue, g_object_ref (message)); - g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message); - return; + if (from_handle == 0) { + empathy_message_set_sender (message, priv->user); + tp_chat_emit_queued_messages (chat); + } else { + empathy_tp_contact_factory_get_from_handle (priv->factory, + from_handle, + tp_chat_got_sender_cb, + message, NULL, G_OBJECT (chat)); } - - DEBUG ("Sender not ready"); - g_queue_push_tail (priv->messages_queue, g_object_ref (message)); - g_signal_connect (sender, "notify::ready", - G_CALLBACK (tp_chat_sender_ready_notify_cb), - chat); } static void @@ -422,7 +268,6 @@ tp_chat_received_cb (TpChannel *channel, { EmpathyTpChat *chat = EMPATHY_TP_CHAT (chat_); EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyMessage *message; if (priv->channel == NULL) return; @@ -447,15 +292,12 @@ tp_chat_received_cb (TpChannel *channel, return; } - message = tp_chat_build_message (chat, - message_id, - message_type, - timestamp, - from_handle, - message_body); - - tp_chat_emit_or_queue_message (chat, message); - g_object_unref (message); + tp_chat_build_message (chat, + message_id, + message_type, + timestamp, + from_handle, + message_body); } static void @@ -468,22 +310,18 @@ tp_chat_sent_cb (TpChannel *channel, { EmpathyTpChat *chat = EMPATHY_TP_CHAT (chat_); EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyMessage *message; if (priv->channel == NULL) return; DEBUG ("Message sent: %s", message_body); - message = tp_chat_build_message (chat, - 0, - message_type, - timestamp, - 0, - message_body); - - tp_chat_emit_or_queue_message (chat, message); - g_object_unref (message); + tp_chat_build_message (chat, + 0, + message_type, + timestamp, + 0, + message_body); } static void @@ -495,7 +333,6 @@ tp_chat_send_error_cb (TpChannel *channel, gpointer user_data, GObject *chat) { - EmpathyMessage *message; EmpathyTpChatPriv *priv = GET_PRIV (chat); if (priv->channel == NULL) @@ -503,15 +340,12 @@ tp_chat_send_error_cb (TpChannel *channel, DEBUG ("Message sent error: %s (%d)", message_body, error_code); - message = tp_chat_build_message (EMPATHY_TP_CHAT (chat), - 0, - message_type, - timestamp, - 0, - message_body); - - g_signal_emit (chat, signals[SEND_ERROR], 0, message, error_code); - g_object_unref (message); + tp_chat_build_message (EMPATHY_TP_CHAT (chat), + 0, + message_type, + timestamp, + 0, + message_body); } static void @@ -529,28 +363,45 @@ tp_chat_send_cb (TpChannel *proxy, } } +typedef struct { + EmpathyTpChat *chat; + TpChannelChatState state; +} StateChangedData; + static void -tp_chat_state_changed_cb (TpChannel *channel, - guint handle, - guint state, - gpointer user_data, - GObject *chat) +tp_chat_state_changed_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *chat) { - EmpathyTpChatPriv *priv = GET_PRIV (chat); - EmpathyContact *contact; + TpChannelChatState state; - if (priv->channel == NULL) + if (error) { + DEBUG ("Error: %s", error->message); return; + } - contact = empathy_contact_factory_get_from_handle (priv->factory, - priv->account, - handle); - + state = GPOINTER_TO_UINT (user_data); DEBUG ("Chat state changed for %s (%d): %d", - empathy_contact_get_name (contact), handle, state); + empathy_contact_get_name (contact), + empathy_contact_get_handle (contact), state); g_signal_emit (chat, signals[CHAT_STATE_CHANGED], 0, contact, state); - g_object_unref (contact); +} + +static void +tp_chat_state_changed_cb (TpChannel *channel, + TpHandle handle, + TpChannelChatState state, + gpointer user_data, + GObject *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + + empathy_tp_contact_factory_get_from_handle (priv->factory, handle, + tp_chat_state_changed_got_contact_cb, GUINT_TO_POINTER (state), + NULL, chat); } static void @@ -576,7 +427,6 @@ tp_chat_list_pending_messages_cb (TpChannel *channel, } for (i = 0; i < messages_list->len; i++) { - EmpathyMessage *message; GValueArray *message_struct; const gchar *message_body; guint message_id; @@ -608,15 +458,12 @@ tp_chat_list_pending_messages_cb (TpChannel *channel, continue; } - message = tp_chat_build_message (chat, - message_id, - message_type, - timestamp, - from_handle, - message_body); - - tp_chat_emit_or_queue_message (chat, message); - g_object_unref (message); + tp_chat_build_message (chat, + message_id, + message_type, + timestamp, + from_handle, + message_body); } if (empty_non_text_content_ids != NULL) { @@ -781,8 +628,6 @@ empathy_tp_chat_set_property (EmpathyTpChat *chat, TpChatProperty *property; guint i; - g_return_if_fail (priv->ready); - for (i = 0; i < priv->properties->len; i++) { property = g_ptr_array_index (priv->properties, i); if (!tp_strdiff (property->name, name)) { @@ -824,64 +669,90 @@ empathy_tp_chat_set_property (EmpathyTpChat *chat, } static void -tp_chat_channel_ready_cb (EmpathyTpChat *chat) +tp_chat_dispose (GObject *object) { - EmpathyTpChatPriv *priv = GET_PRIV (chat); - TpConnection *connection; - guint handle, handle_type; + EmpathyTpChat *self = EMPATHY_TP_CHAT (object); + EmpathyTpChatPriv *priv = GET_PRIV (self); - if (priv->channel == NULL) + if (priv->dispose_has_run) return; - DEBUG ("Channel ready"); - - g_object_get (priv->channel, - "connection", &connection, - "handle", &handle, - "handle_type", &handle_type, - NULL); + priv->dispose_has_run = TRUE; - if (handle_type == TP_HANDLE_TYPE_CONTACT && handle != 0) { - priv->remote_contact = empathy_contact_factory_get_from_handle (priv->factory, - priv->account, - handle); - g_object_notify (G_OBJECT (chat), "remote-contact"); + if (priv->channel != NULL) { + g_signal_handlers_disconnect_by_func (priv->channel, + tp_chat_invalidated_cb, self); + g_object_unref (priv->channel); } + priv->channel = NULL; - if (tp_proxy_has_interface_by_id (priv->channel, - TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP)) { - priv->group = empathy_tp_group_new (priv->channel); - - g_signal_connect (priv->group, "member-added", - G_CALLBACK (tp_chat_member_added_cb), - chat); - g_signal_connect (priv->group, "member-removed", - G_CALLBACK (tp_chat_member_removed_cb), - chat); - g_signal_connect (priv->group, "local-pending", - G_CALLBACK (tp_chat_local_pending_cb), - chat); - empathy_run_until_ready (priv->group); - } else { - priv->members_count = 2; + if (priv->remote_contact != NULL) + g_object_unref (priv->remote_contact); + priv->remote_contact = NULL; + + if (priv->factory != NULL) + g_object_unref (priv->factory); + priv->factory = NULL; + + if (priv->user != NULL); + g_object_unref (priv->user); + priv->user = NULL; + + if (priv->contact_monitor) + g_object_unref (priv->contact_monitor); + priv->contact_monitor = NULL; + + g_queue_foreach (priv->messages_queue, (GFunc) g_object_unref, NULL); + g_queue_clear (priv->messages_queue); + + g_queue_foreach (priv->pending_messages_queue, + (GFunc) g_object_unref, NULL); + g_queue_clear (priv->pending_messages_queue); + + if (G_OBJECT_CLASS (empathy_tp_chat_parent_class)->dispose) + G_OBJECT_CLASS (empathy_tp_chat_parent_class)->dispose (object); +} + +static void +tp_chat_finalize (GObject *object) +{ + EmpathyTpChatPriv *priv = GET_PRIV (object); + guint i; + + DEBUG ("Finalize: %p", object); + + if (priv->properties) { + for (i = 0; i < priv->properties->len; i++) { + TpChatProperty *property; + + property = g_ptr_array_index (priv->properties, i); + g_free (property->name); + if (property->value) { + tp_g_value_slice_free (property->value); + } + g_slice_free (TpChatProperty, property); + } + g_ptr_array_free (priv->properties, TRUE); } - - if (tp_proxy_has_interface_by_id (priv->channel, - TP_IFACE_QUARK_PROPERTIES_INTERFACE)) { - tp_cli_properties_interface_call_list_properties (priv->channel, -1, - tp_chat_list_properties_cb, - NULL, NULL, - G_OBJECT (chat)); - tp_cli_properties_interface_connect_to_properties_changed (priv->channel, - tp_chat_properties_changed_cb, - NULL, NULL, - G_OBJECT (chat), NULL); - tp_cli_properties_interface_connect_to_property_flags_changed (priv->channel, - tp_chat_property_flags_changed_cb, - NULL, NULL, - G_OBJECT (chat), NULL); + + g_queue_free (priv->messages_queue); + g_queue_free (priv->pending_messages_queue); + + G_OBJECT_CLASS (empathy_tp_chat_parent_class)->finalize (object); +} + +static void +tp_chat_check_if_ready (EmpathyTpChat *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + + if (priv->ready || priv->user == NULL || + (priv->members == NULL && priv->remote_contact == NULL)) { + return; } + DEBUG ("Ready!"); + priv->listing_pending_messages = TRUE; tp_cli_channel_type_text_call_list_pending_messages (priv->channel, -1, FALSE, @@ -909,101 +780,184 @@ tp_chat_channel_ready_cb (EmpathyTpChat *chat) tp_chat_state_changed_cb, NULL, NULL, G_OBJECT (chat), NULL); - priv->ready = TRUE; g_object_notify (G_OBJECT (chat), "ready"); } static void -tp_chat_dispose (GObject *object) +tp_chat_update_remote_contact (EmpathyTpChat *chat) { - EmpathyTpChat *self = EMPATHY_TP_CHAT (object); - EmpathyTpChatPriv *priv = GET_PRIV (self); + EmpathyTpChatPriv *priv = GET_PRIV (chat); + EmpathyContact *contact = NULL; + TpHandle self_handle; + TpHandleType handle_type; + GList *l; - if (priv->dispose_has_run) + /* If this is a named chatroom, never pretend it is a private chat */ + tp_channel_get_handle (priv->channel, &handle_type); + if (handle_type == TP_HANDLE_TYPE_ROOM) { return; + } - priv->dispose_has_run = TRUE; - - if (priv->channel != NULL) - { - g_signal_handlers_disconnect_by_func (priv->channel, - tp_chat_invalidated_cb, self); - g_object_unref (priv->channel); - priv->channel = NULL; + /* This is an MSN-like chat where anyone can join the chat at anytime. + * If there is only one non-self contact member, we are in a private + * chat and we set the "remote-contact" property to that contact. If + * there are more, set the "remote-contact" property to NULL and the + * UI will display a contact list. */ + self_handle = tp_channel_group_get_self_handle (priv->channel); + for (l = priv->members; l; l = l->next) { + /* Skip self contact if member */ + if (empathy_contact_get_handle (l->data) == self_handle) { + continue; } - if (priv->remote_contact != NULL) - g_object_unref (priv->remote_contact); + /* We have more than one remote contact, break */ + if (contact != NULL) { + contact = NULL; + break; + } - priv->remote_contact = NULL; + /* If we didn't find yet a remote contact, keep this one */ + contact = l->data; + } - if (priv->group != NULL) - g_object_unref (priv->group); - priv->group = NULL; + if (priv->remote_contact == contact) { + return; + } - if (priv->factory != NULL) - g_object_unref (priv->factory); - priv->factory = NULL; + DEBUG ("Changing remote contact from %p to %p", + priv->remote_contact, contact); - if (priv->user != NULL); - g_object_unref (priv->user); - priv->user = NULL; + if (priv->remote_contact) { + g_object_unref (priv->remote_contact); + } - if (priv->account != NULL); - g_object_unref (priv->account); - priv->account = NULL; + priv->remote_contact = contact ? g_object_ref (contact) : NULL; + g_object_notify (G_OBJECT (chat), "remote-contact"); +} - if (priv->contact_monitor) - g_object_unref (priv->contact_monitor); - priv->contact_monitor = NULL; +static void +tp_chat_got_added_contacts_cb (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + guint i; + const TpIntSet *members; + TpHandle handle; + EmpathyContact *contact; - if (!g_queue_is_empty (priv->messages_queue)) { - EmpathyMessage *message; - EmpathyContact *contact; + if (error) { + DEBUG ("Error: %s", error->message); + return; + } - message = g_queue_peek_head (priv->messages_queue); - contact = empathy_message_get_sender (message); - g_signal_handlers_disconnect_by_func (contact, - tp_chat_sender_ready_notify_cb, object); + members = tp_channel_group_get_members (priv->channel); + for (i = 0; i < n_contacts; i++) { + contact = contacts[i]; + handle = empathy_contact_get_handle (contact); + + /* Make sure the contact is still member */ + if (tp_intset_is_member (members, handle)) { + priv->members = g_list_prepend (priv->members, + g_object_ref (contact)); + g_signal_emit_by_name (chat, "members-changed", + contact, NULL, 0, NULL, FALSE); + } } - g_list_foreach (priv->messages_queue->head, - (GFunc) g_object_unref, NULL); + tp_chat_update_remote_contact (EMPATHY_TP_CHAT (chat)); + tp_chat_check_if_ready (EMPATHY_TP_CHAT (chat)); +} - g_list_foreach (priv->pending_messages_queue->head, - (GFunc) g_object_unref, NULL); +static void +tp_chat_group_members_changed_cb (TpChannel *self, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + guint actor, + guint reason, + EmpathyTpChat *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + EmpathyContact *contact; + TpHandle handle; + guint i; + GList *l; - if (G_OBJECT_CLASS (empathy_tp_chat_parent_class)->dispose) - G_OBJECT_CLASS (empathy_tp_chat_parent_class)->dispose (object); + /* Remove contacts that are not members anymore */ + for (i = 0; i < removed->len; i++) { + for (l = priv->members; l; l = l->next) { + contact = l->data; + handle = empathy_contact_get_handle (contact); + if (handle == g_array_index (removed, TpHandle, i)) { + priv->members = g_list_delete_link (priv->members, l); + g_signal_emit_by_name (chat, "members-changed", + contact, NULL, reason, + message, FALSE); + g_object_unref (contact); + break; + } + } + } + + /* Request added contacts */ + if (added->len > 0) { + empathy_tp_contact_factory_get_from_handles (priv->factory, + added->len, (TpHandle*) added->data, + tp_chat_got_added_contacts_cb, NULL, NULL, + G_OBJECT (chat)); + } + + tp_chat_update_remote_contact (chat); } static void -tp_chat_finalize (GObject *object) +tp_chat_got_remote_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *chat) { - EmpathyTpChatPriv *priv = GET_PRIV (object); - guint i; + EmpathyTpChatPriv *priv = GET_PRIV (chat); - DEBUG ("Finalize: %p", object); + if (error) { + DEBUG ("Error: %s", error->message); + empathy_tp_chat_close (EMPATHY_TP_CHAT (chat)); + return; + } - if (priv->properties) { - for (i = 0; i < priv->properties->len; i++) { - TpChatProperty *property; + priv->remote_contact = g_object_ref (contact); + g_object_notify (chat, "remote-contact"); - property = g_ptr_array_index (priv->properties, i); - g_free (property->name); - if (property->value) { - tp_g_value_slice_free (property->value); - } - g_slice_free (TpChatProperty, property); - } - g_ptr_array_free (priv->properties, TRUE); - } + tp_chat_check_if_ready (EMPATHY_TP_CHAT (chat)); +} - g_queue_free (priv->messages_queue); - g_queue_free (priv->pending_messages_queue); +static void +tp_chat_got_self_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); - G_OBJECT_CLASS (empathy_tp_chat_parent_class)->finalize (object); + if (error) { + DEBUG ("Error: %s", error->message); + empathy_tp_chat_close (EMPATHY_TP_CHAT (chat)); + return; + } + + priv->user = g_object_ref (contact); + empathy_contact_set_is_user (priv->user, TRUE); + tp_chat_check_if_ready (EMPATHY_TP_CHAT (chat)); } static GObject * @@ -1013,26 +967,67 @@ tp_chat_constructor (GType type, { GObject *chat; EmpathyTpChatPriv *priv; - gboolean channel_ready; + TpConnection *connection; + TpHandle handle; chat = G_OBJECT_CLASS (empathy_tp_chat_parent_class)->constructor (type, n_props, props); priv = GET_PRIV (chat); - priv->account = empathy_channel_get_account (priv->channel); - priv->factory = empathy_contact_factory_dup_singleton (); - priv->user = empathy_contact_factory_get_user (priv->factory, priv->account); + connection = tp_channel_borrow_connection (priv->channel); + priv->factory = empathy_tp_contact_factory_dup_singleton (connection); g_signal_connect (priv->channel, "invalidated", G_CALLBACK (tp_chat_invalidated_cb), chat); - g_object_get (priv->channel, "channel-ready", &channel_ready, NULL); - if (channel_ready) { - tp_chat_channel_ready_cb (EMPATHY_TP_CHAT (chat)); + if (tp_proxy_has_interface_by_id (priv->channel, + TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP)) { + const TpIntSet *members; + GArray *handles; + + /* Get self contact from the group's self handle */ + handle = tp_channel_group_get_self_handle (priv->channel); + empathy_tp_contact_factory_get_from_handle (priv->factory, + handle, tp_chat_got_self_contact_cb, + NULL, NULL, chat); + + /* Get initial member contacts */ + members = tp_channel_group_get_members (priv->channel); + handles = tp_intset_to_array (members); + empathy_tp_contact_factory_get_from_handles (priv->factory, + handles->len, (TpHandle*) handles->data, + tp_chat_got_added_contacts_cb, NULL, NULL, chat); + + g_signal_connect (priv->channel, "group-members-changed", + G_CALLBACK (tp_chat_group_members_changed_cb), chat); } else { - g_signal_connect_swapped (priv->channel, "notify::channel-ready", - G_CALLBACK (tp_chat_channel_ready_cb), - chat); + /* Get the self contact from the connection's self handle */ + handle = tp_connection_get_self_handle (connection); + empathy_tp_contact_factory_get_from_handle (priv->factory, + handle, tp_chat_got_self_contact_cb, + NULL, NULL, chat); + + /* Get the remote contact */ + handle = tp_channel_get_handle (priv->channel, NULL); + empathy_tp_contact_factory_get_from_handle (priv->factory, + handle, tp_chat_got_remote_contact_cb, + NULL, NULL, chat); + } + + if (tp_proxy_has_interface_by_id (priv->channel, + TP_IFACE_QUARK_PROPERTIES_INTERFACE)) { + tp_cli_properties_interface_call_list_properties (priv->channel, -1, + tp_chat_list_properties_cb, + NULL, NULL, + G_OBJECT (chat)); + tp_cli_properties_interface_connect_to_properties_changed (priv->channel, + tp_chat_properties_changed_cb, + NULL, NULL, + G_OBJECT (chat), NULL); + tp_cli_properties_interface_connect_to_property_flags_changed (priv->channel, + tp_chat_property_flags_changed_cb, + NULL, NULL, + G_OBJECT (chat), NULL); } return chat; @@ -1107,6 +1102,7 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass) "The remote contact if there is no group iface on the channel", EMPATHY_TYPE_CONTACT, G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_READY, g_param_spec_boolean ("ready", @@ -1203,17 +1199,9 @@ empathy_tp_chat_close (EmpathyTpChat *chat) { EmpathyTpChatPriv *priv = GET_PRIV (chat); /* If there are still messages left, it'll come back.. - We loose the ordering of sent messages though */ - g_signal_handlers_disconnect_by_func (priv->channel, - tp_chat_invalidated_cb, chat); - + * We loose the ordering of sent messages though */ tp_cli_channel_call_close (priv->channel, -1, tp_chat_async_cb, "closing channel", NULL, NULL); - - g_object_unref (priv->channel); - priv->channel = NULL; - - g_signal_emit (chat, signals[DESTROY], 0); } const gchar * @@ -1222,7 +1210,6 @@ empathy_tp_chat_get_id (EmpathyTpChat *chat) EmpathyTpChatPriv *priv = GET_PRIV (chat); g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); - g_return_val_if_fail (priv->ready, NULL); return tp_channel_get_identifier (priv->channel); } @@ -1233,28 +1220,29 @@ empathy_tp_chat_get_remote_contact (EmpathyTpChat *chat) EmpathyTpChatPriv *priv = GET_PRIV (chat); g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); + g_return_val_if_fail (priv->ready, NULL); return priv->remote_contact; } -McAccount * -empathy_tp_chat_get_account (EmpathyTpChat *chat) +TpChannel * +empathy_tp_chat_get_channel (EmpathyTpChat *chat) { EmpathyTpChatPriv *priv = GET_PRIV (chat); - g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), FALSE); + g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); - return priv->account; + return priv->channel; } -TpChannel * -empathy_tp_chat_get_channel (EmpathyTpChat *chat) +TpConnection * +empathy_tp_chat_get_connection (EmpathyTpChat *chat) { EmpathyTpChatPriv *priv = GET_PRIV (chat); g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); - return priv->channel; + return tp_channel_borrow_connection (priv->channel); } gboolean @@ -1267,16 +1255,6 @@ empathy_tp_chat_is_ready (EmpathyTpChat *chat) return priv->ready; } -guint -empathy_tp_chat_get_members_count (EmpathyTpChat *chat) -{ - EmpathyTpChatPriv *priv = GET_PRIV (chat); - - g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), 0); - - return priv->members_count; -} - void empathy_tp_chat_send (EmpathyTpChat *chat, EmpathyMessage *message) @@ -1326,6 +1304,9 @@ empathy_tp_chat_get_pending_messages (EmpathyTpChat *chat) { EmpathyTpChatPriv *priv = GET_PRIV (chat); + g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL); + g_return_val_if_fail (priv->ready, NULL); + return priv->pending_messages_queue->head; } @@ -1346,6 +1327,9 @@ empathy_tp_chat_acknowledge_message (EmpathyTpChat *chat, GList *m; guint id; + g_return_if_fail (EMPATHY_IS_TP_CHAT (chat)); + g_return_if_fail (priv->ready); + if (empathy_message_get_sender (message) == priv->user) goto out; @@ -1373,6 +1357,9 @@ empathy_tp_chat_acknowledge_messages (EmpathyTpChat *chat, guint length; GArray *message_ids; + g_return_if_fail (EMPATHY_IS_TP_CHAT (chat)); + g_return_if_fail (priv->ready); + length = g_list_length ((GList *)messages); if (length == 0) @@ -1402,3 +1389,4 @@ empathy_tp_chat_acknowledge_messages (EmpathyTpChat *chat, g_array_free (message_ids, TRUE); g_list_free (msgs); } + diff --git a/libempathy/empathy-tp-chat.h b/libempathy/empathy-tp-chat.h index 353052923..fadc5f636 100644 --- a/libempathy/empathy-tp-chat.h +++ b/libempathy/empathy-tp-chat.h @@ -57,10 +57,9 @@ EmpathyTpChat *empathy_tp_chat_new (TpChannel *channel void empathy_tp_chat_close (EmpathyTpChat *chat); const gchar * empathy_tp_chat_get_id (EmpathyTpChat *chat); EmpathyContact*empathy_tp_chat_get_remote_contact (EmpathyTpChat *chat); -McAccount * empathy_tp_chat_get_account (EmpathyTpChat *chat); TpChannel * empathy_tp_chat_get_channel (EmpathyTpChat *chat); +TpConnection * empathy_tp_chat_get_connection (EmpathyTpChat *chat); gboolean empathy_tp_chat_is_ready (EmpathyTpChat *chat); -guint empathy_tp_chat_get_members_count (EmpathyTpChat *chat); void empathy_tp_chat_send (EmpathyTpChat *chat, EmpathyMessage *message); void empathy_tp_chat_set_state (EmpathyTpChat *chat, diff --git a/libempathy/empathy-tp-contact-factory.c b/libempathy/empathy-tp-contact-factory.c index f72cc77d1..7735b0f1a 100644 --- a/libempathy/empathy-tp-contact-factory.c +++ b/libempathy/empathy-tp-contact-factory.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,28 +24,20 @@ #include <string.h> #include <telepathy-glib/util.h> -#include <telepathy-glib/connection.h> #include <telepathy-glib/gtypes.h> -#include <libmissioncontrol/mission-control.h> #include <extensions/extensions.h> #include "empathy-tp-contact-factory.h" #include "empathy-utils.h" -#include "empathy-account-manager.h" #define DEBUG_FLAG EMPATHY_DEBUG_TP | EMPATHY_DEBUG_CONTACT #include "empathy-debug.h" #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpContactFactory) typedef struct { - EmpathyAccountManager *account_manager; - McAccount *account; TpConnection *connection; - gboolean ready; - GList *contacts; - EmpathyContact *user; gchar **avatar_mime_types; guint avatar_min_width; @@ -53,15 +45,14 @@ typedef struct { guint avatar_max_width; guint avatar_max_height; guint avatar_max_size; - gboolean can_request_ft; + gboolean can_request_ft; } EmpathyTpContactFactoryPriv; G_DEFINE_TYPE (EmpathyTpContactFactory, empathy_tp_contact_factory, G_TYPE_OBJECT); enum { PROP_0, - PROP_ACCOUNT, - PROP_READY, + PROP_CONNECTION, PROP_MIME_TYPES, PROP_MIN_WIDTH, @@ -71,6 +62,11 @@ enum { PROP_MAX_SIZE }; +static TpContactFeature contact_features[] = { + TP_CONTACT_FEATURE_ALIAS, + TP_CONTACT_FEATURE_PRESENCE, +}; + static EmpathyContact * tp_contact_factory_find_by_handle (EmpathyTpContactFactory *tp_factory, guint handle) @@ -88,14 +84,14 @@ tp_contact_factory_find_by_handle (EmpathyTpContactFactory *tp_factory, } static EmpathyContact * -tp_contact_factory_find_by_id (EmpathyTpContactFactory *tp_factory, - const gchar *id) +tp_contact_factory_find_by_tp_contact (EmpathyTpContactFactory *tp_factory, + TpContact *tp_contact) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); GList *l; for (l = priv->contacts; l; l = l->next) { - if (!tp_strdiff (empathy_contact_get_id (l->data), id)) { + if (empathy_contact_get_tp_contact (l->data) == tp_contact) { return l->data; } } @@ -115,196 +111,13 @@ tp_contact_factory_weak_notify (gpointer data, } static void -tp_contact_factory_presences_table_foreach (const gchar *state_str, - GHashTable *presences_table, - EmpathyContact *contact) -{ - const GValue *message; - const gchar *message_str = NULL; - - empathy_contact_set_presence (contact, - empathy_presence_from_str (state_str)); - - message = g_hash_table_lookup (presences_table, "message"); - if (message) { - message_str = g_value_get_string (message); - } - - if (!EMP_STR_EMPTY (message_str)) { - empathy_contact_set_presence_message (contact, message_str); - } else { - empathy_contact_set_presence_message (contact, NULL); - } -} - -static void -tp_contact_factory_parse_presence_foreach (guint handle, - GValueArray *presence_struct, - EmpathyTpContactFactory *tp_factory) -{ - GHashTable *presences_table; - EmpathyContact *contact; - - contact = tp_contact_factory_find_by_handle (tp_factory, handle); - if (!contact) { - return; - } - - presences_table = g_value_get_boxed (g_value_array_get_nth (presence_struct, 1)); - - g_hash_table_foreach (presences_table, - (GHFunc) tp_contact_factory_presences_table_foreach, - contact); - - DEBUG ("Changing presence for contact %s (%d) to '%s' (%d)", - empathy_contact_get_id (contact), - handle, - empathy_contact_get_presence_message (contact), - empathy_contact_get_presence (contact)); -} - -static void -tp_contact_factory_get_presence_cb (TpConnection *connection, - GHashTable *handle_table, - const GError *error, - gpointer user_data, - GObject *tp_factory) -{ - if (error) { - DEBUG ("Error getting presence: %s", error->message); - if (error->domain == TP_DBUS_ERRORS && - error->code == TP_DBUS_ERROR_NO_INTERFACE) { - guint *handles = user_data; - - /* We have no presence iface, set default presence - * to available */ - while (*handles != 0) { - EmpathyContact *contact; - - contact = tp_contact_factory_find_by_handle ( - (EmpathyTpContactFactory*) tp_factory, - *handles); - if (contact) { - empathy_contact_set_presence (contact, - MC_PRESENCE_AVAILABLE); - } - - handles++; - } - } - - return; - } - - g_hash_table_foreach (handle_table, - (GHFunc) tp_contact_factory_parse_presence_foreach, - EMPATHY_TP_CONTACT_FACTORY (tp_factory)); -} - -static void -tp_contact_factory_presence_update_cb (TpConnection *connection, - GHashTable *handle_table, - gpointer user_data, - GObject *tp_factory) -{ - g_hash_table_foreach (handle_table, - (GHFunc) tp_contact_factory_parse_presence_foreach, - EMPATHY_TP_CONTACT_FACTORY (tp_factory)); -} - -static void tp_contact_factory_set_aliases_cb (TpConnection *connection, const GError *error, gpointer user_data, GObject *tp_factory) { if (error) { - DEBUG ("Error setting alias: %s", error->message); - } -} - -static void -tp_contact_factory_request_aliases_cb (TpConnection *connection, - const gchar **contact_names, - const GError *error, - gpointer user_data, - GObject *tp_factory) -{ - guint *handles = user_data; - guint i = 0; - const gchar **name; - - if (error) { - DEBUG ("Error requesting aliases: %s", error->message); - - /* If we failed to get alias set it to NULL, like that if - * someone is waiting for the name to be ready it won't wait - * infinitely */ - while (*handles != 0) { - EmpathyContact *contact; - - contact = tp_contact_factory_find_by_handle ( - (EmpathyTpContactFactory*) tp_factory, - *handles); - if (contact) { - empathy_contact_set_name (contact, NULL); - } - - handles++; - } - return; - } - - for (name = contact_names; *name; name++) { - EmpathyContact *contact; - - contact = tp_contact_factory_find_by_handle (EMPATHY_TP_CONTACT_FACTORY (tp_factory), - handles[i]); - if (!contact) { - continue; - } - - DEBUG ("Renaming contact %s (%d) to %s (request cb)", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - *name); - - empathy_contact_set_name (contact, *name); - - i++; - } -} - -static void -tp_contact_factory_aliases_changed_cb (TpConnection *connection, - const GPtrArray *renamed_handlers, - gpointer user_data, - GObject *weak_object) -{ - EmpathyTpContactFactory *tp_factory = EMPATHY_TP_CONTACT_FACTORY (weak_object); - guint i; - - for (i = 0; renamed_handlers->len > i; i++) { - guint handle; - const gchar *alias; - GValueArray *renamed_struct; - EmpathyContact *contact; - - renamed_struct = g_ptr_array_index (renamed_handlers, i); - handle = g_value_get_uint (g_value_array_get_nth (renamed_struct, 0)); - alias = g_value_get_string (g_value_array_get_nth (renamed_struct, 1)); - contact = tp_contact_factory_find_by_handle (tp_factory, handle); - - if (!contact) { - /* We don't know this contact, skip */ - continue; - } - - DEBUG ("Renaming contact %s (%d) to %s (changed cb)", - empathy_contact_get_id (contact), - handle, alias); - - empathy_contact_set_name (contact, alias); + DEBUG ("Error: %s", error->message); } } @@ -316,7 +129,7 @@ tp_contact_factory_set_avatar_cb (TpConnection *connection, GObject *tp_factory) { if (error) { - DEBUG ("Error setting avatar: %s", error->message); + DEBUG ("Error: %s", error->message); } } @@ -327,7 +140,7 @@ tp_contact_factory_clear_avatar_cb (TpConnection *connection, GObject *tp_factory) { if (error) { - DEBUG ("Error clearing avatar: %s", error->message); + DEBUG ("Error: %s", error->message); } } @@ -366,7 +179,7 @@ tp_contact_factory_request_avatars_cb (TpConnection *connection, GObject *tp_factory) { if (error) { - DEBUG ("Error requesting avatars: %s", error->message); + DEBUG ("Error: %s", error->message); } } @@ -426,20 +239,19 @@ tp_contact_factory_avatar_tokens_foreach (gpointer key, } static void -tp_contact_factory_get_known_avatar_tokens_cb (TpConnection *connection, - GHashTable *tokens, - const GError *error, - gpointer user_data, - GObject *tp_factory) +tp_contact_factory_got_known_avatar_tokens (EmpathyTpContactFactory *tp_factory, + GHashTable *tokens, + const GError *error) { + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); TokensData data; if (error) { - DEBUG ("Error getting known avatars tokens: %s", error->message); + DEBUG ("Error: %s", error->message); return; } - data.tp_factory = EMPATHY_TP_CONTACT_FACTORY (tp_factory); + data.tp_factory = tp_factory; data.handles = g_array_new (FALSE, FALSE, sizeof (guint)); g_hash_table_foreach (tokens, tp_contact_factory_avatar_tokens_foreach, @@ -450,15 +262,16 @@ tp_contact_factory_get_known_avatar_tokens_cb (TpConnection *connection, /* Request needed avatars */ if (data.handles->len > 0) { - tp_cli_connection_interface_avatars_call_request_avatars (connection, + tp_cli_connection_interface_avatars_call_request_avatars (priv->connection, -1, data.handles, tp_contact_factory_request_avatars_cb, NULL, NULL, - tp_factory); + G_OBJECT (tp_factory)); } g_array_free (data.handles, TRUE); + g_hash_table_destroy (tokens); } static void @@ -528,17 +341,14 @@ tp_contact_factory_update_capabilities (EmpathyTpContactFactory *tp_factory, } static void -tp_contact_factory_get_capabilities_cb (TpConnection *connection, - const GPtrArray *capabilities, - const GError *error, - gpointer user_data, - GObject *weak_object) +tp_contact_factory_got_capabilities (EmpathyTpContactFactory *tp_factory, + GPtrArray *capabilities, + const GError *error) { - EmpathyTpContactFactory *tp_factory = EMPATHY_TP_CONTACT_FACTORY (weak_object); - guint i; + guint i; if (error) { - DEBUG ("Error getting capabilities: %s", error->message); + DEBUG ("Error: %s", error->message); /* FIXME Should set the capabilities of the contacts for which this request * originated to NONE */ return; @@ -562,7 +372,11 @@ tp_contact_factory_get_capabilities_cb (TpConnection *connection, channel_type, generic, specific); + + g_value_array_free (values); } + + g_ptr_array_free (capabilities, TRUE); } static void @@ -596,231 +410,6 @@ tp_contact_factory_capabilities_changed_cb (TpConnection *connection, } static void -tp_contact_factory_request_everything (EmpathyTpContactFactory *tp_factory, - const GArray *handles) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - guint *dup_handles; - - g_return_if_fail (priv->ready); - - dup_handles = g_malloc0 ((handles->len + 1) * sizeof (guint)); - g_memmove (dup_handles, handles->data, handles->len * sizeof (guint)); - tp_cli_connection_interface_presence_call_get_presence (priv->connection, - -1, - handles, - tp_contact_factory_get_presence_cb, - dup_handles, g_free, - G_OBJECT (tp_factory)); - - /* FIXME: Sometimes the dbus call timesout because CM takes - * too much time to request all aliases from the server, - * that's why we increase the timeout here. See fd.o bug #14795 */ - dup_handles = g_malloc0 ((handles->len + 1) * sizeof (guint)); - g_memmove (dup_handles, handles->data, handles->len * sizeof (guint)); - tp_cli_connection_interface_aliasing_call_request_aliases (priv->connection, - 5*60*1000, - handles, - tp_contact_factory_request_aliases_cb, - dup_handles, g_free, - G_OBJECT (tp_factory)); - - tp_cli_connection_interface_avatars_call_get_known_avatar_tokens (priv->connection, - -1, - handles, - tp_contact_factory_get_known_avatar_tokens_cb, - NULL, NULL, - G_OBJECT (tp_factory)); - - tp_cli_connection_interface_capabilities_call_get_capabilities (priv->connection, - -1, - handles, - tp_contact_factory_get_capabilities_cb, - NULL, NULL, - G_OBJECT (tp_factory)); -} - -static void -tp_contact_factory_list_free (gpointer data) -{ - GList *l = data; - - g_list_foreach (l, (GFunc) g_object_unref, NULL); - g_list_free (l); -} - -static void -tp_contact_factory_request_handles_cb (TpConnection *connection, - const GArray *handles, - const GError *error, - gpointer user_data, - GObject *tp_factory) -{ - GList *contacts = user_data; - GList *l; - guint i = 0; - - if (error) { - DEBUG ("Failed to request handles: %s", error->message); - return; - } - - for (l = contacts; l; l = l->next) { - guint handle; - - handle = g_array_index (handles, guint, i); - empathy_contact_set_handle (l->data, handle); - - i++; - } - - tp_contact_factory_request_everything (EMPATHY_TP_CONTACT_FACTORY (tp_factory), - handles); -} - -static void -tp_contact_factory_inspect_handles_cb (TpConnection *connection, - const gchar **ids, - const GError *error, - gpointer user_data, - GObject *tp_factory) -{ - const gchar **id; - GList *contacts = user_data; - GList *l; - - if (error) { - DEBUG ("Failed to inspect handles: %s", error->message); - return; - } - - id = ids; - for (l = contacts; l; l = l->next) { - empathy_contact_set_id (l->data, *id); - id++; - } -} - -static void -tp_contact_factory_disconnect_contact_foreach (gpointer data, - gpointer user_data) -{ - EmpathyContact *contact = data; - - empathy_contact_set_presence (contact, MC_PRESENCE_UNSET); - empathy_contact_set_handle (contact, 0); -} - -static void -tp_contact_factory_connection_invalidated_cb (EmpathyTpContactFactory *tp_factory) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - - DEBUG ("Connection invalidated"); - - g_object_unref (priv->connection); - priv->connection = NULL; - priv->ready = FALSE; - g_object_notify (G_OBJECT (tp_factory), "ready"); - - - g_list_foreach (priv->contacts, - tp_contact_factory_disconnect_contact_foreach, - tp_factory); -} - -static void -tp_contact_factory_ready (EmpathyTpContactFactory *tp_factory) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - GList *l; - GArray *handle_needed; - GArray *id_needed; - GList *handle_needed_contacts = NULL; - GList *id_needed_contacts = NULL; - - DEBUG ("Connection ready"); - - priv->ready = TRUE; - g_object_notify (G_OBJECT (tp_factory), "ready"); - - /* Connect signals */ - tp_cli_connection_interface_aliasing_connect_to_aliases_changed (priv->connection, - tp_contact_factory_aliases_changed_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - tp_cli_connection_interface_avatars_connect_to_avatar_updated (priv->connection, - tp_contact_factory_avatar_updated_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - tp_cli_connection_interface_avatars_connect_to_avatar_retrieved (priv->connection, - tp_contact_factory_avatar_retrieved_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - tp_cli_connection_interface_presence_connect_to_presence_update (priv->connection, - tp_contact_factory_presence_update_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - tp_cli_connection_interface_capabilities_connect_to_capabilities_changed (priv->connection, - tp_contact_factory_capabilities_changed_cb, - NULL, NULL, - G_OBJECT (tp_factory), - NULL); - - /* Request needed info for all existing contacts */ - handle_needed = g_array_new (TRUE, FALSE, sizeof (gchar*)); - id_needed = g_array_new (FALSE, FALSE, sizeof (guint)); - for (l = priv->contacts; l; l = l->next) { - EmpathyContact *contact; - guint handle; - const gchar *id; - - contact = l->data; - handle = empathy_contact_get_handle (contact); - id = empathy_contact_get_id (contact); - if (handle == 0) { - g_assert (!EMP_STR_EMPTY (id)); - g_array_append_val (handle_needed, id); - handle_needed_contacts = g_list_prepend (handle_needed_contacts, - g_object_ref (contact)); - } - if (EMP_STR_EMPTY (id)) { - g_array_append_val (id_needed, handle); - id_needed_contacts = g_list_prepend (id_needed_contacts, - g_object_ref (contact)); - } - } - handle_needed_contacts = g_list_reverse (handle_needed_contacts); - id_needed_contacts = g_list_reverse (id_needed_contacts); - - tp_cli_connection_call_request_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - (const gchar**) handle_needed->data, - tp_contact_factory_request_handles_cb, - handle_needed_contacts, tp_contact_factory_list_free, - G_OBJECT (tp_factory)); - - tp_cli_connection_call_inspect_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - id_needed, - tp_contact_factory_inspect_handles_cb, - id_needed_contacts, tp_contact_factory_list_free, - G_OBJECT (tp_factory)); - - tp_contact_factory_request_everything ((EmpathyTpContactFactory*) tp_factory, - id_needed); - - g_array_free (handle_needed, TRUE); - g_array_free (id_needed, TRUE); -} - -static void get_requestable_channel_classes_cb (TpProxy *connection, const GValue *value, const GError *error, @@ -834,7 +423,6 @@ get_requestable_channel_classes_cb (TpProxy *connection, if (error != NULL) { DEBUG ("Error: %s", error->message); - tp_contact_factory_ready (self); return; } @@ -877,8 +465,6 @@ get_requestable_channel_classes_cb (TpProxy *connection, } break; } - - tp_contact_factory_ready (self); } static void @@ -909,303 +495,377 @@ tp_contact_factory_got_avatar_requirements_cb (TpConnection *proxy, priv->avatar_max_height = max_height; priv->avatar_max_size = max_size; } - - /* Can we request file transfer channels? */ - tp_cli_dbus_properties_call_get (priv->connection, -1, - TP_IFACE_CONNECTION_INTERFACE_REQUESTS, - "RequestableChannelClasses", - get_requestable_channel_classes_cb, NULL, NULL, - G_OBJECT (tp_factory)); } static void -tp_contact_factory_got_self_handle_cb (TpConnection *proxy, - guint handle, - const GError *error, - gpointer user_data, - GObject *tp_factory) +tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory, + EmpathyContact *contact) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + TpHandle self_handle; + TpHandle handle; + GArray handles = {(gchar*) &handle, 1}; + GHashTable *tokens; + GPtrArray *capabilities; + GError *error = NULL; + + /* Keep a weak ref to that contact */ + g_object_weak_ref (G_OBJECT (contact), + tp_contact_factory_weak_notify, + tp_factory); + priv->contacts = g_list_prepend (priv->contacts, contact); - if (error) { - DEBUG ("Failed to get self handles: %s", error->message); - return; + /* The contact keeps a ref to its factory */ + g_object_set_data_full (G_OBJECT (contact), "empathy-factory", + g_object_ref (tp_factory), + g_object_unref); + + /* Set the FT capability */ + if (priv->can_request_ft) { + EmpathyCapabilities caps; + + caps = empathy_contact_get_capabilities (contact); + caps |= EMPATHY_CAPABILITIES_FT; + + empathy_contact_set_capabilities (contact, caps); } - empathy_contact_set_handle (priv->user, handle); + /* Set is-user property. Note that it could still be the handle is + * different from the connection's self handle, in the case the handle + * comes from a group interface. */ + self_handle = tp_connection_get_self_handle (priv->connection); + handle = empathy_contact_get_handle (contact); + empathy_contact_set_is_user (contact, self_handle == handle); + + /* FIXME: This should be done by TpContact */ + tp_cli_connection_interface_avatars_run_get_known_avatar_tokens (priv->connection, + -1, + &handles, + &tokens, + &error, + NULL); + tp_contact_factory_got_known_avatar_tokens (tp_factory, tokens, error); + g_clear_error (&error); + + tp_cli_connection_interface_capabilities_run_get_capabilities (priv->connection, + -1, + &handles, + &capabilities, + &error, + NULL); + tp_contact_factory_got_capabilities (tp_factory, capabilities, error); + g_clear_error (&error); - /* Get avatar requirements for this connection */ - tp_cli_connection_interface_avatars_call_get_avatar_requirements ( - priv->connection, - -1, - tp_contact_factory_got_avatar_requirements_cb, - NULL, NULL, - tp_factory); + DEBUG ("Contact added: %s (%d)", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact)); } -static void -tp_contact_factory_connection_ready_cb (EmpathyTpContactFactory *tp_factory) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); +typedef union { + EmpathyTpContactFactoryContactsByIdCb ids_cb; + EmpathyTpContactFactoryContactsByHandleCb handles_cb; + EmpathyTpContactFactoryContactCb contact_cb; +} GetContactsCb; - /* Get our own handle */ - tp_cli_connection_call_get_self_handle (priv->connection, - -1, - tp_contact_factory_got_self_handle_cb, - NULL, NULL, - G_OBJECT (tp_factory)); -} +typedef struct { + EmpathyTpContactFactory *tp_factory; + GetContactsCb callback; + gpointer user_data; + GDestroyNotify destroy; +} GetContactsData; static void -tp_contact_factory_status_updated (EmpathyTpContactFactory *tp_factory) +get_contacts_data_free (gpointer user_data) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - gboolean connection_ready; - MissionControl *mc; + GetContactsData *data = user_data; - if (priv->connection) { - /* We already have our connection object */ - return; + if (data->destroy) { + data->destroy (data->user_data); } + g_object_unref (data->tp_factory); - mc = empathy_mission_control_dup_singleton (); - priv->connection = mission_control_get_tpconnection (mc, priv->account, NULL); - if (!priv->connection) { - return; - } + g_slice_free (GetContactsData, data); +} - /* We got a new connection, wait for it to be ready */ - g_signal_connect_swapped (priv->connection, "invalidated", - G_CALLBACK (tp_contact_factory_connection_invalidated_cb), - tp_factory); +static EmpathyContact * +dup_contact_for_tp_contact (EmpathyTpContactFactory *tp_factory, + TpContact *tp_contact) +{ + EmpathyContact *contact; + + contact = tp_contact_factory_find_by_tp_contact (tp_factory, + tp_contact); - g_object_get (priv->connection, "connection-ready", &connection_ready, NULL); - if (connection_ready) { - tp_contact_factory_connection_ready_cb (tp_factory); + if (contact != NULL) { + g_object_ref (contact); } else { - g_signal_connect_swapped (priv->connection, "notify::connection-ready", - G_CALLBACK (tp_contact_factory_connection_ready_cb), - tp_factory); + contact = empathy_contact_new (tp_contact); + tp_contact_factory_add_contact (tp_factory, contact); } - g_object_unref (mc); + return contact; } -static void -tp_contact_factory_account_connection_cb (EmpathyAccountManager *account_manager, - McAccount *account, - TpConnectionStatusReason reason, - TpConnectionStatus current, - TpConnectionStatus previous, - EmpathyTpContactFactory *tp_factory) +static EmpathyContact ** +contacts_array_new (EmpathyTpContactFactory *tp_factory, + guint n_contacts, + TpContact * const * contacts) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + EmpathyContact **ret; + guint i; - if (account && empathy_account_equal (account, priv->account)) { - tp_contact_factory_status_updated (tp_factory); + ret = g_new0 (EmpathyContact *, n_contacts); + for (i = 0; i < n_contacts; i++) { + ret[i] = dup_contact_for_tp_contact (tp_factory, contacts[i]); } + + return ret; } static void -tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory, - EmpathyContact *contact) +contacts_array_free (guint n_contacts, + EmpathyContact **contacts) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - - g_object_weak_ref (G_OBJECT (contact), - tp_contact_factory_weak_notify, - tp_factory); - priv->contacts = g_list_prepend (priv->contacts, contact); + guint i; - DEBUG ("Contact added: %s (%d)", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact)); + for (i = 0; i < n_contacts; i++) { + g_object_unref (contacts[i]); + } + g_free (contacts); } static void -tp_contact_factory_hold_handles_cb (TpConnection *connection, - const GError *error, - gpointer userdata, - GObject *tp_factory) +get_contacts_by_id_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + const gchar * const *requested_ids, + GHashTable *failed_id_errors, + const GError *error, + gpointer user_data, + GObject *weak_object) { - if (error) { - DEBUG ("Failed to hold handles: %s", error->message); + GetContactsData *data = user_data; + EmpathyContact **empathy_contacts; + + empathy_contacts = contacts_array_new (data->tp_factory, + n_contacts, contacts); + if (data->callback.ids_cb) { + data->callback.ids_cb (data->tp_factory, + n_contacts, empathy_contacts, + requested_ids, + failed_id_errors, + error, + data->user_data, weak_object); } + + contacts_array_free (n_contacts, empathy_contacts); } -EmpathyContact * -empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory) +void +empathy_tp_contact_factory_get_from_ids (EmpathyTpContactFactory *tp_factory, + guint n_ids, + const gchar * const *ids, + EmpathyTpContactFactoryContactsByIdCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + GetContactsData *data; - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); - - return g_object_ref (priv->user); + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); + g_return_if_fail (ids != NULL); + + data = g_slice_new (GetContactsData); + data->callback.ids_cb = callback; + data->user_data = user_data; + data->destroy = destroy; + data->tp_factory = g_object_ref (tp_factory); + tp_connection_get_contacts_by_id (priv->connection, + n_ids, ids, + G_N_ELEMENTS (contact_features), + contact_features, + get_contacts_by_id_cb, + data, + (GDestroyNotify) get_contacts_data_free, + weak_object); } static void -contact_created (EmpathyTpContactFactory *self, - EmpathyContact *contact) +get_contact_by_id_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + const gchar * const *requested_ids, + GHashTable *failed_id_errors, + const GError *error, + gpointer user_data, + GObject *weak_object) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (self); - - if (priv->can_request_ft) - { - /* Set the FT capability */ - /* FIXME: We should use the futur ContactCapabilities interface */ - EmpathyCapabilities caps; - - caps = empathy_contact_get_capabilities (contact); - caps |= EMPATHY_CAPABILITIES_FT; + GetContactsData *data = user_data; + EmpathyContact *contact = NULL; - empathy_contact_set_capabilities (contact, caps); - } + if (n_contacts == 1) { + contact = dup_contact_for_tp_contact (data->tp_factory, + contacts[0]); + } + else if (error == NULL) { + GHashTableIter iter; + gpointer value; + + g_hash_table_iter_init (&iter, failed_id_errors); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + if (value) { + error = value; + break; + } + } + } - tp_contact_factory_add_contact (self, contact); + if (data->callback.contact_cb) { + data->callback.contact_cb (data->tp_factory, + contact, + error, + data->user_data, weak_object); + } } -EmpathyContact * +void empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory, - const gchar *id) + const gchar *id, + EmpathyTpContactFactoryContactCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - EmpathyContact *contact; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); - g_return_val_if_fail (id != NULL, NULL); - - /* Check if the contact already exists */ - contact = tp_contact_factory_find_by_id (tp_factory, id); - if (contact) { - return g_object_ref (contact); - } - - /* Create new contact */ - contact = g_object_new (EMPATHY_TYPE_CONTACT, - "account", priv->account, - "id", id, - NULL); - contact_created (tp_factory, contact); - - if (priv->ready) { - const gchar *contact_ids[] = {id, NULL}; - GList *contacts; - - contacts = g_list_prepend (NULL, g_object_ref (contact)); - tp_cli_connection_call_request_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - contact_ids, - tp_contact_factory_request_handles_cb, - contacts, tp_contact_factory_list_free, - G_OBJECT (tp_factory)); - } + GetContactsData *data; - return contact; + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); + g_return_if_fail (id != NULL); + + data = g_slice_new (GetContactsData); + data->callback.contact_cb = callback; + data->user_data = user_data; + data->destroy = destroy; + data->tp_factory = g_object_ref (tp_factory); + tp_connection_get_contacts_by_id (priv->connection, + 1, &id, + G_N_ELEMENTS (contact_features), + contact_features, + get_contact_by_id_cb, + data, + (GDestroyNotify) get_contacts_data_free, + weak_object); } -EmpathyContact * -empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory, - guint handle) +static void +get_contacts_by_handle_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *weak_object) { - EmpathyContact *contact; - GArray *handles; - GList *contacts; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); - - handles = g_array_new (FALSE, FALSE, sizeof (guint)); - g_array_append_val (handles, handle); - - contacts = empathy_tp_contact_factory_get_from_handles (tp_factory, handles); - g_array_free (handles, TRUE); - - contact = contacts ? contacts->data : NULL; - g_list_free (contacts); + GetContactsData *data = user_data; + EmpathyContact **empathy_contacts; + + empathy_contacts = contacts_array_new (data->tp_factory, + n_contacts, contacts); + if (data->callback.handles_cb) { + data->callback.handles_cb (data->tp_factory, + n_contacts, empathy_contacts, + n_failed, failed, + error, + data->user_data, weak_object); + } - return contact; + contacts_array_free (n_contacts, empathy_contacts); } -GList * +void empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory, - const GArray *handles) + guint n_handles, + const TpHandle *handles, + EmpathyTpContactFactoryContactsByHandleCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - GList *contacts = NULL; - GArray *new_handles; - GList *new_contacts = NULL; - guint i; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); - g_return_val_if_fail (handles != NULL, NULL); + GetContactsData *data; - /* Search all contacts we already have */ - new_handles = g_array_new (FALSE, FALSE, sizeof (guint)); - for (i = 0; i < handles->len; i++) { - EmpathyContact *contact; - guint handle; + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); + g_return_if_fail (handles != NULL); + + data = g_slice_new (GetContactsData); + data->callback.handles_cb = callback; + data->user_data = user_data; + data->destroy = destroy; + data->tp_factory = g_object_ref (tp_factory); + tp_connection_get_contacts_by_handle (priv->connection, + n_handles, handles, + G_N_ELEMENTS (contact_features), + contact_features, + get_contacts_by_handle_cb, + data, + (GDestroyNotify) get_contacts_data_free, + weak_object); +} - handle = g_array_index (handles, guint, i); - if (handle == 0) { - continue; - } +static void +get_contact_by_handle_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + GetContactsData *data = user_data; + EmpathyContact *contact = NULL; - contact = tp_contact_factory_find_by_handle (tp_factory, handle); - if (contact) { - contacts = g_list_prepend (contacts, g_object_ref (contact)); - } else { - g_array_append_val (new_handles, handle); - } + if (n_contacts == 1) { + contact = dup_contact_for_tp_contact (data->tp_factory, + contacts[0]); } - if (new_handles->len == 0) { - g_array_free (new_handles, TRUE); - return contacts; + if (data->callback.contact_cb) { + data->callback.contact_cb (data->tp_factory, + contact, + error, + data->user_data, weak_object); } +} - /* Create new contacts */ - for (i = 0; i < new_handles->len; i++) { - EmpathyContact *contact; - guint handle; - - handle = g_array_index (new_handles, guint, i); - - contact = g_object_new (EMPATHY_TYPE_CONTACT, - "account", priv->account, - "handle", handle, - NULL); - contact_created (tp_factory, contact); - contacts = g_list_prepend (contacts, contact); - new_contacts = g_list_prepend (new_contacts, g_object_ref (contact)); - } - new_contacts = g_list_reverse (new_contacts); - - if (priv->ready) { - /* Get the IDs of all new handles */ - tp_cli_connection_call_inspect_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - new_handles, - tp_contact_factory_inspect_handles_cb, - new_contacts, tp_contact_factory_list_free, - G_OBJECT (tp_factory)); - - /* Hold all new handles. */ - /* FIXME: Should be unholded when removed from the factory */ - tp_cli_connection_call_hold_handles (priv->connection, - -1, - TP_HANDLE_TYPE_CONTACT, - new_handles, - tp_contact_factory_hold_handles_cb, - NULL, NULL, - G_OBJECT (tp_factory)); - - tp_contact_factory_request_everything (tp_factory, new_handles); - } +void +empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory, + TpHandle handle, + EmpathyTpContactFactoryContactCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + GetContactsData *data; - g_array_free (new_handles, TRUE); + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); - return contacts; + data = g_slice_new (GetContactsData); + data->callback.contact_cb = callback; + data->user_data = user_data; + data->destroy = destroy; + data->tp_factory = g_object_ref (tp_factory); + tp_connection_get_contacts_by_handle (priv->connection, + 1, &handle, + G_N_ELEMENTS (contact_features), + contact_features, + get_contact_by_handle_cb, + data, + (GDestroyNotify) get_contacts_data_free, + weak_object); } void @@ -1219,9 +879,6 @@ empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory, g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - g_return_if_fail (priv->ready); - g_return_if_fail (empathy_account_equal (empathy_contact_get_account (contact), - priv->account)); handle = empathy_contact_get_handle (contact); @@ -1257,7 +914,6 @@ empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory, EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); - g_return_if_fail (priv->ready); if (data && size > 0 && size < G_MAXUINT) { GArray avatar; @@ -1265,8 +921,8 @@ empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory, avatar.data = (gchar*) data; avatar.len = size; - DEBUG ("Setting avatar on account %s", - mc_account_get_unique_name (priv->account)); + DEBUG ("Setting avatar on connection %s", + tp_proxy_get_object_path (TP_PROXY (priv->connection))); tp_cli_connection_interface_avatars_call_set_avatar (priv->connection, -1, @@ -1276,8 +932,8 @@ empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory, NULL, NULL, G_OBJECT (tp_factory)); } else { - DEBUG ("Clearing avatar on account %s", - mc_account_get_unique_name (priv->account)); + DEBUG ("Clearing avatar on connection %s", + tp_proxy_get_object_path (TP_PROXY (priv->connection))); tp_cli_connection_interface_avatars_call_clear_avatar (priv->connection, -1, @@ -1287,16 +943,6 @@ empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory, } } -gboolean -empathy_tp_contact_factory_is_ready (EmpathyTpContactFactory *tp_factory) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), FALSE); - - return priv->ready; -} - static void tp_contact_factory_get_property (GObject *object, guint param_id, @@ -1306,11 +952,8 @@ tp_contact_factory_get_property (GObject *object, EmpathyTpContactFactoryPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); - break; - case PROP_READY: - g_value_set_boolean (value, priv->ready); + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); break; case PROP_MIME_TYPES: g_value_set_boxed (value, priv->avatar_mime_types); @@ -1345,8 +988,8 @@ tp_contact_factory_set_property (GObject *object, EmpathyTpContactFactoryPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - priv->account = g_object_ref (g_value_get_object (value)); + case PROP_CONNECTION: + priv->connection = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -1360,12 +1003,7 @@ tp_contact_factory_finalize (GObject *object) EmpathyTpContactFactoryPriv *priv = GET_PRIV (object); GList *l; - DEBUG ("Finalized: %p (%s)", object, - mc_account_get_normalized_name (priv->account)); - - g_signal_handlers_disconnect_by_func (priv->account_manager, - tp_contact_factory_account_connection_cb, - object); + DEBUG ("Finalized: %p", object); for (l = priv->contacts; l; l = l->next) { g_object_weak_unref (G_OBJECT (l->data), @@ -1374,16 +1012,8 @@ tp_contact_factory_finalize (GObject *object) } g_list_free (priv->contacts); - g_object_unref (priv->account_manager); - g_object_unref (priv->account); - g_object_unref (priv->user); - - if (priv->connection) { - g_signal_handlers_disconnect_by_func (priv->connection, - tp_contact_factory_connection_invalidated_cb, - object); - g_object_unref (priv->connection); - } + + g_object_unref (priv->connection); g_strfreev (priv->avatar_mime_types); @@ -1401,11 +1031,35 @@ tp_contact_factory_constructor (GType type, tp_factory = G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->constructor (type, n_props, props); priv = GET_PRIV (tp_factory); - priv->ready = FALSE; - priv->user = empathy_contact_new (priv->account); - empathy_contact_set_is_user (priv->user, TRUE); - tp_contact_factory_add_contact ((EmpathyTpContactFactory*) tp_factory, priv->user); - tp_contact_factory_status_updated (EMPATHY_TP_CONTACT_FACTORY (tp_factory)); + /* FIXME: This should be moved to TpContact */ + tp_cli_connection_interface_avatars_connect_to_avatar_updated (priv->connection, + tp_contact_factory_avatar_updated_cb, + NULL, NULL, + tp_factory, + NULL); + tp_cli_connection_interface_avatars_connect_to_avatar_retrieved (priv->connection, + tp_contact_factory_avatar_retrieved_cb, + NULL, NULL, + tp_factory, + NULL); + tp_cli_connection_interface_capabilities_connect_to_capabilities_changed (priv->connection, + tp_contact_factory_capabilities_changed_cb, + NULL, NULL, + tp_factory, + NULL); + + + /* FIXME: This should be moved to TpConnection */ + tp_cli_connection_interface_avatars_call_get_avatar_requirements (priv->connection, + -1, + tp_contact_factory_got_avatar_requirements_cb, + NULL, NULL, + tp_factory); + tp_cli_dbus_properties_call_get (priv->connection, -1, + TP_IFACE_CONNECTION_INTERFACE_REQUESTS, + "RequestableChannelClasses", + get_requestable_channel_classes_cb, NULL, NULL, + G_OBJECT (tp_factory)); return tp_factory; } @@ -1421,29 +1075,20 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) object_class->set_property = tp_contact_factory_set_property; g_object_class_install_property (object_class, - PROP_ACCOUNT, - g_param_spec_object ("account", - "Factory's Account", - "The account associated with the factory", - MC_TYPE_ACCOUNT, + PROP_CONNECTION, + g_param_spec_object ("connection", + "Factory's Connection", + "The connection associated with the factory", + TP_TYPE_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, - PROP_READY, - g_param_spec_boolean ("ready", - "Whether the factory is ready", - "TRUE once the factory is ready to be used", - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (object_class, PROP_MIME_TYPES, g_param_spec_boxed ("avatar-mime-types", "Supported MIME types for avatars", "Types of images that may be set as " - "avatars on this connection. Only valid " - "once 'ready' becomes TRUE.", + "avatars on this connection.", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -1451,8 +1096,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) PROP_MIN_WIDTH, g_param_spec_uint ("avatar-min-width", "Minimum width for avatars", - "Minimum width of avatar that may be set. " - "Only valid once 'ready' becomes TRUE.", + "Minimum width of avatar that may be set.", 0, G_MAXUINT, 0, @@ -1462,8 +1106,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) PROP_MIN_HEIGHT, g_param_spec_uint ("avatar-min-height", "Minimum height for avatars", - "Minimum height of avatar that may be set. " - "Only valid once 'ready' becomes TRUE.", + "Minimum height of avatar that may be set.", 0, G_MAXUINT, 0, @@ -1474,8 +1117,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) g_param_spec_uint ("avatar-max-width", "Maximum width for avatars", "Maximum width of avatar that may be set " - "or 0 if there is no maximum. " - "Only valid once 'ready' becomes TRUE.", + "or 0 if there is no maximum.", 0, G_MAXUINT, 0, @@ -1486,8 +1128,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) g_param_spec_uint ("avatar-max-height", "Maximum height for avatars", "Maximum height of avatar that may be set " - "or 0 if there is no maximum. " - "Only valid once 'ready' becomes TRUE.", + "or 0 if there is no maximum.", 0, G_MAXUINT, 0, @@ -1498,8 +1139,7 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) g_param_spec_uint ("avatar-max-size", "Maximum size for avatars in bytes", "Maximum file size of avatar that may be " - "set or 0 if there is no maximum. " - "Only valid once 'ready' becomes TRUE.", + "set or 0 if there is no maximum.", 0, G_MAXUINT, 0, @@ -1517,20 +1157,68 @@ empathy_tp_contact_factory_init (EmpathyTpContactFactory *tp_factory) EMPATHY_TYPE_TP_CONTACT_FACTORY, EmpathyTpContactFactoryPriv); tp_factory->priv = priv; - priv->account_manager = empathy_account_manager_dup_singleton (); + priv->can_request_ft = FALSE; +} - g_signal_connect (priv->account_manager, "account-connection-changed", - G_CALLBACK (tp_contact_factory_account_connection_cb), - tp_factory); +static GHashTable *factories = NULL; - priv->can_request_ft = FALSE; +static void +tp_contact_factory_connection_invalidated_cb (TpProxy *connection, + guint domain, + gint code, + gchar *message, + gpointer user_data) +{ + DEBUG ("Message: %s", message); + g_hash_table_remove (factories, connection); +} + +static void +tp_contact_factory_connection_weak_notify_cb (gpointer connection, + GObject *where_the_object_was) +{ + g_hash_table_remove (factories, connection); +} + +static void +tp_contact_factory_remove_connection (gpointer connection) +{ + g_signal_handlers_disconnect_by_func (connection, + tp_contact_factory_connection_invalidated_cb, NULL); + g_object_unref (connection); } EmpathyTpContactFactory * -empathy_tp_contact_factory_new (McAccount *account) +empathy_tp_contact_factory_dup_singleton (TpConnection *connection) { - return g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY, - "account", account, - NULL); + EmpathyTpContactFactory *tp_factory; + + g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL); + + if (factories == NULL) { + factories = g_hash_table_new_full (empathy_proxy_hash, + empathy_proxy_equal, + tp_contact_factory_remove_connection, + NULL); + } + + tp_factory = g_hash_table_lookup (factories, connection); + if (tp_factory == NULL) { + tp_factory = g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY, + "connection", connection, + NULL); + g_hash_table_insert (factories, g_object_ref (connection), + tp_factory); + g_object_weak_ref (G_OBJECT (tp_factory), + tp_contact_factory_connection_weak_notify_cb, + connection); + g_signal_connect (connection, "invalidated", + G_CALLBACK (tp_contact_factory_connection_invalidated_cb), + NULL); + } else { + g_object_ref (tp_factory); + } + + return tp_factory; } diff --git a/libempathy/empathy-tp-contact-factory.h b/libempathy/empathy-tp-contact-factory.h index 92e7c2980..91ff2f9e7 100644 --- a/libempathy/empathy-tp-contact-factory.h +++ b/libempathy/empathy-tp-contact-factory.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,7 +24,7 @@ #include <glib.h> -#include <libmissioncontrol/mc-account.h> +#include <telepathy-glib/connection.h> #include "empathy-contact.h" @@ -49,15 +49,58 @@ struct _EmpathyTpContactFactoryClass { GObjectClass parent_class; }; +typedef void (*EmpathyTpContactFactoryContactsByIdCb) (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + const gchar * const * requested_ids, + GHashTable *failed_id_errors, + const GError *error, + gpointer user_data, + GObject *weak_object); + +typedef void (*EmpathyTpContactFactoryContactsByHandleCb) (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *weak_object); + +typedef void (*EmpathyTpContactFactoryContactCb) (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object); + GType empathy_tp_contact_factory_get_type (void) G_GNUC_CONST; -EmpathyTpContactFactory *empathy_tp_contact_factory_new (McAccount *account); -EmpathyContact * empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory); -EmpathyContact * empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory, - const gchar *id); -EmpathyContact * empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory, - guint handle); -GList * empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory, - const GArray *handles); +EmpathyTpContactFactory *empathy_tp_contact_factory_dup_singleton (TpConnection *connection); +void empathy_tp_contact_factory_get_from_ids (EmpathyTpContactFactory *tp_factory, + guint n_ids, + const gchar * const *ids, + EmpathyTpContactFactoryContactsByIdCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object); +void empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory, + guint n_handles, + const TpHandle *handles, + EmpathyTpContactFactoryContactsByHandleCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object); +void empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory, + const gchar *id, + EmpathyTpContactFactoryContactCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object); +void empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory, + TpHandle handle, + EmpathyTpContactFactoryContactCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object); void empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory, EmpathyContact *contact, const gchar *alias); @@ -65,7 +108,6 @@ void empathy_tp_contact_factory_set_avatar (EmpathyTpC const gchar *data, gsize size, const gchar *mime_type); -gboolean empathy_tp_contact_factory_is_ready (EmpathyTpContactFactory *tp_factory); G_END_DECLS diff --git a/libempathy/empathy-tp-contact-list.c b/libempathy/empathy-tp-contact-list.c index d4b99e4c4..dd160224c 100644 --- a/libempathy/empathy-tp-contact-list.c +++ b/libempathy/empathy-tp-contact-list.c @@ -1,7 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2007 Xavier Claessens <xclaesse@gmail.com> - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -31,8 +31,8 @@ #include <telepathy-glib/dbus.h> #include "empathy-tp-contact-list.h" +#include "empathy-tp-contact-factory.h" #include "empathy-contact-list.h" -#include "empathy-tp-group.h" #include "empathy-utils.h" #define DEBUG_FLAG EMPATHY_DEBUG_TP | EMPATHY_DEBUG_CONTACT @@ -40,18 +40,16 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpContactList) typedef struct { - McAccount *account; + EmpathyTpContactFactory *factory; TpConnection *connection; const gchar *protocol_group; - gboolean ready; - EmpathyTpGroup *publish; - EmpathyTpGroup *subscribe; - GList *members; - GList *pendings; - - GList *groups; - GHashTable *contacts_groups; + TpChannel *publish; + TpChannel *subscribe; + GHashTable *members; /* handle -> EmpathyContact */ + GHashTable *pendings; /* handle -> EmpathyContact */ + GHashTable *groups; /* group name -> TpChannel */ + GHashTable *add_to_group; /* group name -> GArray of handles */ } EmpathyTpContactListPriv; typedef enum { @@ -63,376 +61,535 @@ typedef enum { static void tp_contact_list_iface_init (EmpathyContactListIface *iface); enum { - DESTROY, - LAST_SIGNAL -}; - -enum { PROP_0, - PROP_ACCOUNT, + PROP_CONNECTION, }; -static guint signals[LAST_SIGNAL]; - G_DEFINE_TYPE_WITH_CODE (EmpathyTpContactList, empathy_tp_contact_list, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST, tp_contact_list_iface_init)); static void -tp_contact_list_group_destroy_cb (EmpathyTpGroup *group, - EmpathyTpContactList *list) +tp_contact_list_group_invalidated_cb (TpChannel *channel, + guint domain, + gint code, + gchar *message, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + const TpIntSet *members; + TpIntSetIter iter; + const gchar *group_name; + + group_name = tp_channel_get_identifier (channel); + DEBUG ("Group %s invalidated. Message: %s", group_name, message); + + /* Signal that all members are not in that group anymore */ + members = tp_channel_group_get_members (channel); + tp_intset_iter_init (&iter, members); + while (tp_intset_iter_next (&iter)) { + EmpathyContact *contact; + + contact = g_hash_table_lookup (priv->members, + GUINT_TO_POINTER (iter.element)); + if (contact == NULL) { + continue; + } - DEBUG ("Group destroyed: %s", empathy_tp_group_get_name (group)); + DEBUG ("Contact %s (%d) removed from group %s", + empathy_contact_get_id (contact), iter.element, + group_name); + g_signal_emit_by_name (list, "groups-changed", contact, + group_name, + FALSE); + } - priv->groups = g_list_remove (priv->groups, group); - g_object_unref (group); + g_hash_table_remove (priv->groups, group_name); } static void -tp_contact_list_group_member_added_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_group_ready_cb (TpChannel *channel, + const GError *error, + gpointer list) { - EmpathyTpContactListPriv *priv = GET_PRIV (list); - const gchar *group_name; - GList **groups; + EmpathyTpContactListPriv *priv = GET_PRIV (list); + const gchar *group_name; - if (!g_list_find (priv->members, contact)) { + if (error) { + DEBUG ("Error: %s", error->message); + g_object_unref (channel); return; } + + group_name = tp_channel_get_identifier (channel); + g_hash_table_insert (priv->groups, (gpointer) group_name, channel); + DEBUG ("Group %s added", group_name); - groups = g_hash_table_lookup (priv->contacts_groups, contact); - if (!groups) { - groups = g_slice_new0 (GList*); - g_hash_table_insert (priv->contacts_groups, - g_object_ref (contact), - groups); - } + g_signal_connect (channel, "invalidated", + G_CALLBACK (tp_contact_list_group_invalidated_cb), + list); - group_name = empathy_tp_group_get_name (group); - if (!g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp)) { - DEBUG ("Contact %s (%d) added to group %s", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - group_name); - *groups = g_list_prepend (*groups, g_strdup (group_name)); - g_signal_emit_by_name (list, "groups-changed", contact, - group_name, - TRUE); + if (priv->add_to_group) { + GArray *handles; + + handles = g_hash_table_lookup (priv->add_to_group, group_name); + if (handles) { + DEBUG ("Adding initial members to group %s", group_name); + tp_cli_channel_interface_group_call_add_members (channel, + -1, handles, NULL, NULL, NULL, NULL, NULL); + g_hash_table_remove (priv->add_to_group, group_name); + } } } static void -tp_contact_list_group_member_removed_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_group_members_changed_cb (TpChannel *channel, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + guint actor, + guint reason, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - const gchar *group_name; - GList **groups, *l; + const gchar *group_name; + gint i; - if (!g_list_find (priv->members, contact)) { - return; - } + group_name = tp_channel_get_identifier (channel); - groups = g_hash_table_lookup (priv->contacts_groups, contact); - if (!groups) { - return; - } + for (i = 0; i < added->len; i++) { + EmpathyContact *contact; + TpHandle handle; + + handle = g_array_index (added, TpHandle, i); + contact = g_hash_table_lookup (priv->members, + GUINT_TO_POINTER (handle)); + if (contact == NULL) { + continue; + } + + DEBUG ("Contact %s (%d) added to group %s", + empathy_contact_get_id (contact), handle, group_name); + g_signal_emit_by_name (list, "groups-changed", contact, + group_name, + TRUE); + } + + for (i = 0; i < removed->len; i++) { + EmpathyContact *contact; + TpHandle handle; + + handle = g_array_index (removed, TpHandle, i); + contact = g_hash_table_lookup (priv->members, + GUINT_TO_POINTER (handle)); + if (contact == NULL) { + continue; + } - group_name = empathy_tp_group_get_name (group); - if ((l = g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp))) { DEBUG ("Contact %s (%d) removed from group %s", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - group_name); - g_free (l->data); - *groups = g_list_delete_link (*groups, l); + empathy_contact_get_id (contact), handle, group_name); + g_signal_emit_by_name (list, "groups-changed", contact, group_name, FALSE); - } + } } -static EmpathyTpGroup * -tp_contact_list_find_group (EmpathyTpContactList *list, - const gchar *group) +static void +tp_contact_list_group_add_channel (EmpathyTpContactList *list, + const gchar *object_path, + const gchar *channel_type, + TpHandleType handle_type, + guint handle) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList *l; + TpChannel *channel; - for (l = priv->groups; l; l = l->next) { - if (!tp_strdiff (group, empathy_tp_group_get_name (l->data))) { - return l->data; - } + /* Only accept server-side contact groups */ + if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) || + handle_type != TP_HANDLE_TYPE_GROUP) { + return; + } + + channel = tp_channel_new (priv->connection, + object_path, channel_type, + handle_type, handle, NULL); + + /* TpChannel emits initial set of members just before being ready */ + g_signal_connect (channel, "group-members-changed", + G_CALLBACK (tp_contact_list_group_members_changed_cb), + list); + + /* Give the ref to the callback */ + tp_channel_call_when_ready (channel, + tp_contact_list_group_ready_cb, + list); +} + +static void +tp_contact_list_group_request_channel_cb (TpConnection *connection, + const gchar *object_path, + const GError *error, + gpointer user_data, + GObject *list) +{ + /* The new channel will be handled in NewChannel cb. Here we only + * handle the error if RequestChannel failed */ + if (error) { + DEBUG ("Error: %s", error->message); + return; } - return NULL; } -static TpContactListType -tp_contact_list_get_type (EmpathyTpContactList *list, - EmpathyTpGroup *group) +static void +tp_contact_list_group_request_handles_cb (TpConnection *connection, + const GArray *handles, + const GError *error, + gpointer user_data, + GObject *list) { - const gchar *name; + TpHandle channel_handle; - name = empathy_tp_group_get_name (group); - if (!tp_strdiff (name, "subscribe")) { - return TP_CONTACT_LIST_TYPE_SUBSCRIBE; - } else if (!tp_strdiff (name, "publish")) { - return TP_CONTACT_LIST_TYPE_PUBLISH; + if (error) { + DEBUG ("Error: %s", error->message); + return; } - return TP_CONTACT_LIST_TYPE_UNKNOWN; + channel_handle = g_array_index (handles, TpHandle, 0); + tp_cli_connection_call_request_channel (connection, -1, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_GROUP, + channel_handle, + TRUE, + tp_contact_list_group_request_channel_cb, + NULL, NULL, + list); } +/* This function takes ownership of handles array */ static void -tp_contact_list_add_member (EmpathyTpContactList *list, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message) +tp_contact_list_group_add (EmpathyTpContactList *list, + const gchar *group_name, + GArray *handles) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList *l; + TpChannel *channel; + const gchar *names[] = {group_name, NULL}; + + /* Search the channel for that group name */ + channel = g_hash_table_lookup (priv->groups, group_name); + if (channel) { + tp_cli_channel_interface_group_call_add_members (channel, -1, + handles, NULL, NULL, NULL, NULL, NULL); + g_array_free (handles, TRUE); + return; + } - /* Add to the list and emit signal */ - priv->members = g_list_prepend (priv->members, g_object_ref (contact)); - g_signal_emit_by_name (list, "members-changed", - contact, actor, reason, message, - TRUE); + /* That group does not exist yet, we have to: + * 1) Request an handle for the group name + * 2) Request a channel + * 3) When NewChannel is emitted, add handles in members + */ + g_hash_table_insert (priv->add_to_group, + g_strdup (group_name), + handles); + tp_cli_connection_call_request_handles (priv->connection, -1, + TP_HANDLE_TYPE_GROUP, names, + tp_contact_list_group_request_handles_cb, + NULL, NULL, + G_OBJECT (list)); +} + +static void +tp_contact_list_got_added_members_cb (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *list) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); + guint i; - /* This contact is now member, implicitly accept pending. */ - if (g_list_find (priv->pendings, contact)) { - empathy_tp_group_add_member (priv->publish, contact, ""); + if (error) { + DEBUG ("Error: %s", error->message); + return; } - /* Update groups of the contact */ - for (l = priv->groups; l; l = l->next) { - if (empathy_tp_group_is_member (l->data, contact)) { - tp_contact_list_group_member_added_cb (l->data, contact, - NULL, 0, NULL, - list); + for (i = 0; i < n_contacts; i++) { + EmpathyContact *contact = contacts[i]; + TpHandle handle; + + handle = empathy_contact_get_handle (contact); + if (g_hash_table_lookup (priv->members, GUINT_TO_POINTER (handle))) + continue; + + /* Add to the list and emit signal */ + g_hash_table_insert (priv->members, GUINT_TO_POINTER (handle), + g_object_ref (contact)); + g_signal_emit_by_name (list, "members-changed", contact, + 0, 0, NULL, TRUE); + + /* This contact is now member, implicitly accept pending. */ + if (g_hash_table_lookup (priv->pendings, GUINT_TO_POINTER (handle))) { + GArray handles = {(gchar*) &handle, 1}; + + tp_cli_channel_interface_group_call_add_members (priv->publish, + -1, &handles, NULL, NULL, NULL, NULL, NULL); } } } static void -tp_contact_list_added_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_got_local_pending_cb (EmpathyTpContactFactory *factory, + guint n_contacts, + EmpathyContact * const * contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - TpContactListType list_type; - - list_type = tp_contact_list_get_type (list, group); - DEBUG ("Contact %s (%d) added to list type %d", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - list_type); - - /* We now get the presence of that contact, add it to members */ - if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && - !g_list_find (priv->members, contact)) { - tp_contact_list_add_member (list, contact, actor, reason, message); + guint i; + + if (error) { + DEBUG ("Error: %s", error->message); + return; } - /* We now send our presence to that contact, remove it from pendings */ - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && - g_list_find (priv->pendings, contact)) { - g_signal_emit_by_name (list, "pendings-changed", - contact, actor, reason, message, - FALSE); - priv->pendings = g_list_remove (priv->pendings, contact); - g_object_unref (contact); + for (i = 0; i < n_contacts; i++) { + EmpathyContact *contact = contacts[i]; + TpHandle handle; + const gchar *message; + TpChannelGroupChangeReason reason; + + handle = empathy_contact_get_handle (contact); + if (g_hash_table_lookup (priv->members, GUINT_TO_POINTER (handle))) { + GArray handles = {(gchar*) &handle, 1}; + + /* This contact is already member, auto accept. */ + tp_cli_channel_interface_group_call_add_members (priv->publish, + -1, &handles, NULL, NULL, NULL, NULL, NULL); + } + else if (tp_channel_group_get_local_pending_info (priv->publish, + handle, + NULL, + &reason, + &message)) { + /* Add contact to pendings */ + g_hash_table_insert (priv->pendings, GUINT_TO_POINTER (handle), + g_object_ref (contact)); + g_signal_emit_by_name (list, "pendings-changed", contact, + contact, reason, message, TRUE); + } } } static void -tp_contact_list_removed_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_remove_handle (EmpathyTpContactList *list, + GHashTable *table, + TpHandle handle) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - TpContactListType list_type; - - list_type = tp_contact_list_get_type (list, group); - DEBUG ("Contact %s (%d) removed from list type %d", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - list_type); - - /* This contact refuses to send us his presence, remove from members. */ - if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && - g_list_find (priv->members, contact)) { - g_signal_emit_by_name (list, "members-changed", - contact, actor, reason, message, - FALSE); - priv->members = g_list_remove (priv->members, contact); - g_object_unref (contact); - } + EmpathyContact *contact; + const gchar *signal; + + if (table == priv->pendings) + signal = "pendings-changed"; + else if (table == priv->members) + signal = "members-changed"; + else + return; - /* We refuse to send our presence to that contact, remove from pendings */ - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && - g_list_find (priv->pendings, contact)) { - g_signal_emit_by_name (list, "pendings-changed", - contact, actor, reason, message, + contact = g_hash_table_lookup (table, GUINT_TO_POINTER (handle)); + if (contact) { + g_object_ref (contact); + g_hash_table_remove (table, GUINT_TO_POINTER (handle)); + g_signal_emit_by_name (list, signal, contact, 0, 0, NULL, FALSE); - priv->pendings = g_list_remove (priv->pendings, contact); g_object_unref (contact); } } static void -tp_contact_list_pending_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - const gchar *message, - EmpathyTpContactList *list) +tp_contact_list_publish_group_members_changed_cb (TpChannel *channel, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + TpHandle actor, + TpChannelGroupChangeReason reason, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - TpContactListType list_type; + guint i; - list_type = tp_contact_list_get_type (list, group); - DEBUG ("Contact %s (%d) pending in list type %d", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - list_type); + /* We now send our presence to those contacts, remove them from pendings */ + for (i = 0; i < added->len; i++) { + tp_contact_list_remove_handle (list, priv->pendings, + g_array_index (added, TpHandle, i)); + } - /* We want this contact in our contact list but we don't get its - * presence yet. Add to members anyway. */ - if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && - !g_list_find (priv->members, contact)) { - tp_contact_list_add_member (list, contact, actor, reason, message); + /* We refuse to send our presence to those contacts, remove from pendings */ + for (i = 0; i < removed->len; i++) { + tp_contact_list_remove_handle (list, priv->pendings, + g_array_index (added, TpHandle, i)); } - /* This contact wants our presence, auto accept if he is member, - * otherwise he is pending. */ - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && - !g_list_find (priv->pendings, contact)) { - if (g_list_find (priv->members, contact)) { - empathy_tp_group_add_member (priv->publish, contact, ""); - } else { - priv->pendings = g_list_prepend (priv->pendings, - g_object_ref (contact)); - g_signal_emit_by_name (list, "pendings-changed", - contact, actor, reason, message, - TRUE); - } + /* Those contacts want our presence, auto accept those that are already + * member, otherwise add in pendings. */ + if (local_pending->len > 0) { + empathy_tp_contact_factory_get_from_handles (priv->factory, + local_pending->len, (TpHandle*) local_pending->data, + tp_contact_list_got_local_pending_cb, NULL, NULL, + G_OBJECT (list)); } } static void -tp_contact_list_invalidated_cb (TpConnection *connection, - guint domain, - gint code, - gchar *message, - EmpathyTpContactList *list) +tp_contact_list_publish_request_channel_cb (TpConnection *connection, + const gchar *object_path, + const GError *error, + gpointer user_data, + GObject *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList *l; - DEBUG ("Connection invalidated"); - - /* Remove all contacts */ - for (l = priv->members; l; l = l->next) { - g_signal_emit_by_name (list, "members-changed", l->data, - NULL, 0, NULL, - FALSE); - g_object_unref (l->data); - } - for (l = priv->pendings; l; l = l->next) { - g_signal_emit_by_name (list, "pendings-changed", l->data, - NULL, 0, NULL, - FALSE); - g_object_unref (l->data); + if (error) { + DEBUG ("Error: %s", error->message); + return; } - g_list_free (priv->members); - g_list_free (priv->pendings); - priv->members = NULL; - priv->pendings = NULL; - /* Tell the world to not use us anymore */ - g_signal_emit (list, signals[DESTROY], 0); + priv->publish = tp_channel_new (connection, object_path, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_LIST, + GPOINTER_TO_UINT (user_data), + NULL); + + /* TpChannel emits initial set of members just before being ready */ + g_signal_connect (priv->publish, "group-members-changed", + G_CALLBACK (tp_contact_list_publish_group_members_changed_cb), + list); } static void -tp_contact_list_group_list_free (GList **groups) +tp_contact_list_publish_request_handle_cb (TpConnection *connection, + const GArray *handles, + const GError *error, + gpointer user_data, + GObject *list) { - g_list_foreach (*groups, (GFunc) g_free, NULL); - g_list_free (*groups); - g_slice_free (GList*, groups); + TpHandle handle; + + if (error) { + DEBUG ("Error: %s", error->message); + return; + } + + handle = g_array_index (handles, TpHandle, 0); + tp_cli_connection_call_request_channel (connection, -1, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_LIST, + handle, + TRUE, + tp_contact_list_publish_request_channel_cb, + GUINT_TO_POINTER (handle), NULL, + list); } static void -tp_contact_list_add_channel (EmpathyTpContactList *list, - const gchar *object_path, - const gchar *channel_type, - TpHandleType handle_type, - guint handle) +tp_contact_list_subscribe_group_members_changed_cb (TpChannel *channel, + gchar *message, + GArray *added, + GArray *removed, + GArray *local_pending, + GArray *remote_pending, + guint actor, + guint reason, + EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - TpChannel *channel; - EmpathyTpGroup *group; - const gchar *group_name; - GList *contacts, *l; + guint i; + + /* We now get the presence of those contacts, add them to members */ + if (added->len > 0) { + empathy_tp_contact_factory_get_from_handles (priv->factory, + added->len, (TpHandle*) added->data, + tp_contact_list_got_added_members_cb, NULL, NULL, + G_OBJECT (list)); + } - if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) != 0 || - handle_type != TP_HANDLE_TYPE_GROUP) { - return; + /* Those contacts refuse to send us their presence, remove from members. */ + for (i = 0; i < removed->len; i++) { + tp_contact_list_remove_handle (list, priv->members, + g_array_index (added, TpHandle, i)); } - channel = tp_channel_new (priv->connection, - object_path, channel_type, - handle_type, handle, NULL); + /* We want those contacts in our contact list but we don't get their + * presence yet. Add to members anyway. */ + if (remote_pending->len > 0) { + empathy_tp_contact_factory_get_from_handles (priv->factory, + remote_pending->len, (TpHandle*) remote_pending->data, + tp_contact_list_got_added_members_cb, NULL, NULL, + G_OBJECT (list)); + } +} - group = empathy_tp_group_new (channel); - empathy_run_until_ready (group); - g_object_unref (channel); +static void +tp_contact_list_subscribe_request_channel_cb (TpConnection *connection, + const gchar *object_path, + const GError *error, + gpointer user_data, + GObject *list) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); - /* Check if already exists */ - group_name = empathy_tp_group_get_name (group); - if (tp_contact_list_find_group (list, group_name)) { - g_object_unref (group); + if (error) { + DEBUG ("Error: %s", error->message); return; } - /* Add the group */ - DEBUG ("New server-side group: %s", group_name); - priv->groups = g_list_prepend (priv->groups, group); - g_signal_connect (group, "member-added", - G_CALLBACK (tp_contact_list_group_member_added_cb), - list); - g_signal_connect (group, "member-removed", - G_CALLBACK (tp_contact_list_group_member_removed_cb), - list); - g_signal_connect (group, "destroy", - G_CALLBACK (tp_contact_list_group_destroy_cb), + priv->subscribe = tp_channel_new (connection, object_path, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_LIST, + GPOINTER_TO_UINT (user_data), + NULL); + + /* TpChannel emits initial set of members just before being ready */ + g_signal_connect (priv->subscribe, "group-members-changed", + G_CALLBACK (tp_contact_list_subscribe_group_members_changed_cb), list); +} - /* Get initial members */ - contacts = empathy_tp_group_get_members (group); - for (l = contacts; l; l = l->next) { - tp_contact_list_group_member_added_cb (group, l->data, - NULL, 0, NULL, - list); - g_object_unref (l->data); +static void +tp_contact_list_subscribe_request_handle_cb (TpConnection *connection, + const GArray *handles, + const GError *error, + gpointer user_data, + GObject *list) +{ + TpHandle handle; + + if (error) { + DEBUG ("Error: %s", error->message); + return; } - g_list_free (contacts); + + handle = g_array_index (handles, TpHandle, 0); + tp_cli_connection_call_request_channel (connection, -1, + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, + TP_HANDLE_TYPE_LIST, + handle, + TRUE, + tp_contact_list_subscribe_request_channel_cb, + GUINT_TO_POINTER (handle), NULL, + list); } static void @@ -445,13 +602,9 @@ tp_contact_list_new_channel_cb (TpConnection *proxy, gpointer user_data, GObject *list) { - EmpathyTpContactListPriv *priv = GET_PRIV (list); - - if (!suppress_handler && priv->ready) { - tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list), - object_path, channel_type, - handle_type, handle); - } + tp_contact_list_group_add_channel (EMPATHY_TP_CONTACT_LIST (list), + object_path, channel_type, + handle_type, handle); } static void @@ -461,8 +614,7 @@ tp_contact_list_list_channels_cb (TpConnection *connection, gpointer user_data, GObject *list) { - EmpathyTpContactListPriv *priv = GET_PRIV (list); - guint i; + guint i; if (error) { DEBUG ("Error: %s", error->message); @@ -482,151 +634,10 @@ tp_contact_list_list_channels_cb (TpConnection *connection, handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2)); handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3)); - tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list), - object_path, channel_type, - handle_type, handle); - } - - priv->ready = TRUE; -} - -static void -tp_contact_list_request_channel_cb (TpConnection *connection, - const gchar *object_path, - const GError *error, - gpointer user_data, - GObject *weak_object) -{ - EmpathyTpContactList *list = EMPATHY_TP_CONTACT_LIST (weak_object); - EmpathyTpContactListPriv *priv = GET_PRIV (list); - EmpathyTpGroup *group; - TpChannel *channel; - TpContactListType list_type; - GList *contacts, *l; - - if (error) { - DEBUG ("Error: %s", error->message); - return; - } - - channel = tp_channel_new (connection, object_path, - TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, - TP_HANDLE_TYPE_LIST, - GPOINTER_TO_UINT (user_data), - NULL); - group = empathy_tp_group_new (channel); - empathy_run_until_ready (group); - - list_type = tp_contact_list_get_type (list, group); - if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && !priv->publish) { - DEBUG ("Got publish list"); - priv->publish = group; - - /* Publish is the list of contacts to who we send our - * presence. Makes no sense to be in remote-pending */ - g_signal_connect (group, "local-pending", - G_CALLBACK (tp_contact_list_pending_cb), - list); - - contacts = empathy_tp_group_get_local_pendings (group); - for (l = contacts; l; l = l->next) { - EmpathyPendingInfo *info = l->data; - tp_contact_list_pending_cb (group, - info->member, - info->actor, - 0, - info->message, - list); - empathy_pending_info_free (info); - } - g_list_free (contacts); - } - else if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && !priv->subscribe) { - DEBUG ("Got subscribe list"); - priv->subscribe = group; - - /* Subscribe is the list of contacts from who we - * receive presence. Makes no sense to be in - * local-pending */ - g_signal_connect (group, "remote-pending", - G_CALLBACK (tp_contact_list_pending_cb), - list); - - contacts = empathy_tp_group_get_remote_pendings (group); - for (l = contacts; l; l = l->next) { - tp_contact_list_pending_cb (group, - l->data, - NULL, 0, - NULL, list); - g_object_unref (l->data); - } - g_list_free (contacts); - } else { - DEBUG ("Type of contact list channel unknown or aleady " - "have that list: %s", - empathy_tp_group_get_name (group)); - g_object_unref (group); - return; + tp_contact_list_group_add_channel (EMPATHY_TP_CONTACT_LIST (list), + object_path, channel_type, + handle_type, handle); } - - /* For all list types when need to get members */ - g_signal_connect (group, "member-added", - G_CALLBACK (tp_contact_list_added_cb), - list); - g_signal_connect (group, "member-removed", - G_CALLBACK (tp_contact_list_removed_cb), - list); - - contacts = empathy_tp_group_get_members (group); - for (l = contacts; l; l = l->next) { - tp_contact_list_added_cb (group, - l->data, - NULL, 0, NULL, - list); - g_object_unref (l->data); - } - g_list_free (contacts); -} - -static void -tp_contact_list_request_handle_cb (TpConnection *connection, - const GArray *handles, - const GError *error, - gpointer user_data, - GObject *list) -{ - guint handle; - - if (error) { - DEBUG ("Error: %s", error->message); - return; - } - - handle = g_array_index (handles, guint, 0); - tp_cli_connection_call_request_channel (connection, -1, - TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, - TP_HANDLE_TYPE_LIST, - handle, - TRUE, - tp_contact_list_request_channel_cb, - GUINT_TO_POINTER (handle), NULL, - list); -} - -static void -tp_contact_list_request_list (EmpathyTpContactList *list, - const gchar *type) -{ - EmpathyTpContactListPriv *priv = GET_PRIV (list); - const gchar *names[] = {type, NULL}; - - tp_cli_connection_call_request_handles (priv->connection, - -1, - TP_HANDLE_TYPE_LIST, - names, - tp_contact_list_request_handle_cb, - NULL, NULL, - G_OBJECT (list)); } static void @@ -634,6 +645,8 @@ tp_contact_list_finalize (GObject *object) { EmpathyTpContactListPriv *priv; EmpathyTpContactList *list; + GHashTableIter iter; + gpointer channel; list = EMPATHY_TP_CONTACT_LIST (object); priv = GET_PRIV (list); @@ -646,49 +659,55 @@ tp_contact_list_finalize (GObject *object) if (priv->publish) { g_object_unref (priv->publish); } - if (priv->account) { - g_object_unref (priv->account); - } + if (priv->connection) { - g_signal_handlers_disconnect_by_func (priv->connection, - tp_contact_list_invalidated_cb, - object); g_object_unref (priv->connection); } - g_hash_table_destroy (priv->contacts_groups); - g_list_foreach (priv->groups, (GFunc) g_object_unref, NULL); - g_list_free (priv->groups); - g_list_foreach (priv->members, (GFunc) g_object_unref, NULL); - g_list_free (priv->members); - g_list_foreach (priv->pendings, (GFunc) g_object_unref, NULL); - g_list_free (priv->pendings); + if (priv->factory) { + g_object_unref (priv->factory); + } + + g_hash_table_iter_init (&iter, priv->groups); + while (g_hash_table_iter_next (&iter, NULL, &channel)) { + g_signal_handlers_disconnect_by_func (channel, + tp_contact_list_group_invalidated_cb, list); + } + + g_hash_table_destroy (priv->groups); + g_hash_table_destroy (priv->members); + g_hash_table_destroy (priv->pendings); + g_hash_table_destroy (priv->add_to_group); G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object); } static void -tp_contact_list_connection_ready (TpConnection *connection, - const GError *error, - gpointer list) +tp_contact_list_constructed (GObject *list) { - EmpathyTpContactListPriv *priv = GET_PRIV (list); - if (error) { - tp_contact_list_invalidated_cb (connection, - error->domain, - error->code, - error->message, - EMPATHY_TP_CONTACT_LIST (list)); - return; - } + EmpathyTpContactListPriv *priv = GET_PRIV (list); + gchar *protocol_name = NULL; + const gchar *names[] = {NULL, NULL}; - g_signal_connect (priv->connection, "invalidated", - G_CALLBACK (tp_contact_list_invalidated_cb), - list); + priv->factory = empathy_tp_contact_factory_dup_singleton (priv->connection); - tp_contact_list_request_list (list, "publish"); - tp_contact_list_request_list (list, "subscribe"); + names[0] = "publish"; + tp_cli_connection_call_request_handles (priv->connection, + -1, + TP_HANDLE_TYPE_LIST, + names, + tp_contact_list_publish_request_handle_cb, + NULL, NULL, + G_OBJECT (list)); + names[0] = "subscribe"; + tp_cli_connection_call_request_handles (priv->connection, + -1, + TP_HANDLE_TYPE_LIST, + names, + tp_contact_list_subscribe_request_handle_cb, + NULL, NULL, + G_OBJECT (list)); tp_cli_connection_call_list_channels (priv->connection, -1, tp_contact_list_list_channels_cb, @@ -699,39 +718,15 @@ tp_contact_list_connection_ready (TpConnection *connection, tp_contact_list_new_channel_cb, NULL, NULL, list, NULL); -} - -static void -tp_contact_list_constructed (GObject *list) -{ - - EmpathyTpContactListPriv *priv = GET_PRIV (list); - MissionControl *mc; - guint status; - McProfile *profile; - const gchar *protocol_name; - - /* Get the connection. status==0 means CONNECTED */ - mc = empathy_mission_control_dup_singleton (); - status = mission_control_get_connection_status (mc, priv->account, NULL); - g_return_if_fail (status == 0); - priv->connection = mission_control_get_tpconnection (mc, priv->account, NULL); - g_return_if_fail (priv->connection != NULL); - g_object_unref (mc); - - tp_connection_call_when_ready (priv->connection, - tp_contact_list_connection_ready, - list); /* Check for protocols that does not support contact groups. We can * put all contacts into a special group in that case. * FIXME: Default group should be an information in the profile */ - profile = mc_account_get_profile (priv->account); - protocol_name = mc_profile_get_protocol_name (profile); - if (strcmp (protocol_name, "local-xmpp") == 0) { + tp_connection_parse_object_path (priv->connection, &protocol_name, NULL); + if (!tp_strdiff (protocol_name, "local-xmpp")) { priv->protocol_group = _("People nearby"); } - g_object_unref (profile); + g_free (protocol_name); } static void @@ -743,8 +738,8 @@ tp_contact_list_get_property (GObject *object, EmpathyTpContactListPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -761,8 +756,8 @@ tp_contact_list_set_property (GObject *object, EmpathyTpContactListPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - priv->account = g_object_ref (g_value_get_object (value)); + case PROP_CONNECTION: + priv->connection = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -781,50 +776,63 @@ empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass) object_class->set_property = tp_contact_list_set_property; g_object_class_install_property (object_class, - PROP_ACCOUNT, - g_param_spec_object ("account", - "The Account", - "The account associated with the contact list", - MC_TYPE_ACCOUNT, + PROP_CONNECTION, + g_param_spec_object ("connection", + "The Connection", + "The connection associated with the contact list", + TP_TYPE_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - signals[DESTROY] = - g_signal_new ("destroy", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - g_type_class_add_private (object_class, sizeof (EmpathyTpContactListPriv)); } static void +tp_contact_list_array_free (gpointer handles) +{ + g_array_free (handles, TRUE); +} + +static void empathy_tp_contact_list_init (EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (list, EMPATHY_TYPE_TP_CONTACT_LIST, EmpathyTpContactListPriv); list->priv = priv; - priv->contacts_groups = g_hash_table_new_full (g_direct_hash, - g_direct_equal, - (GDestroyNotify) g_object_unref, - (GDestroyNotify) tp_contact_list_group_list_free); + + /* Map group's name to group's TpChannel. The group name string is owned + * by the TpChannel object */ + priv->groups = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, + (GDestroyNotify) g_object_unref); + + /* Map contact's handle to EmpathyContact object */ + priv->members = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify) g_object_unref); + + /* Map contact's handle to EmpathyContact object */ + priv->pendings = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify) g_object_unref); + + /* Map group's name to GArray of handle */ + priv->add_to_group = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, + tp_contact_list_array_free); } EmpathyTpContactList * -empathy_tp_contact_list_new (McAccount *account) +empathy_tp_contact_list_new (TpConnection *connection) { return g_object_new (EMPATHY_TYPE_TP_CONTACT_LIST, - "account", account, + "connection", connection, NULL); } -McAccount * -empathy_tp_contact_list_get_account (EmpathyTpContactList *list) +TpConnection * +empathy_tp_contact_list_get_connection (EmpathyTpContactList *list) { EmpathyTpContactListPriv *priv; @@ -832,7 +840,7 @@ empathy_tp_contact_list_get_account (EmpathyTpContactList *list) priv = GET_PRIV (list); - return priv->account; + return priv->connection; } static void @@ -841,15 +849,18 @@ tp_contact_list_add (EmpathyContactList *list, const gchar *message) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpHandle handle; + GArray handles = {(gchar *) &handle, 1}; - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - + handle = empathy_contact_get_handle (contact); if (priv->subscribe) { - empathy_tp_group_add_member (priv->subscribe, contact, message); + tp_cli_channel_interface_group_call_add_members (priv->subscribe, + -1, &handles, message, NULL, NULL, NULL, NULL); } - - if (priv->publish && g_list_find (priv->pendings, contact)) { - empathy_tp_group_add_member (priv->publish, contact, message); + if (priv->publish && + g_hash_table_lookup (priv->pendings, GUINT_TO_POINTER (handle))) { + tp_cli_channel_interface_group_call_add_members (priv->publish, + -1, &handles, message, NULL, NULL, NULL, NULL); } } @@ -859,14 +870,17 @@ tp_contact_list_remove (EmpathyContactList *list, const gchar *message) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpHandle handle; + GArray handles = {(gchar *) &handle, 1}; - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - + handle = empathy_contact_get_handle (contact); if (priv->subscribe) { - empathy_tp_group_remove_member (priv->subscribe, contact, message); + tp_cli_channel_interface_group_call_remove_members (priv->subscribe, + -1, &handles, message, NULL, NULL, NULL, NULL); } if (priv->publish) { - empathy_tp_group_remove_member (priv->publish, contact, message); + tp_cli_channel_interface_group_call_remove_members (priv->publish, + -1, &handles, message, NULL, NULL, NULL, NULL); } } @@ -874,44 +888,40 @@ static GList * tp_contact_list_get_members (EmpathyContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + GList *ret; - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - - g_list_foreach (priv->members, (GFunc) g_object_ref, NULL); - return g_list_copy (priv->members); + ret = g_hash_table_get_values (priv->members); + g_list_foreach (ret, (GFunc) g_object_ref, NULL); + return ret; } static GList * tp_contact_list_get_pendings (EmpathyContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); + GList *ret; - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); - - g_list_foreach (priv->pendings, (GFunc) g_object_ref, NULL); - return g_list_copy (priv->pendings); + ret = g_hash_table_get_values (priv->pendings); + g_list_foreach (ret, (GFunc) g_object_ref, NULL); + return ret; } static GList * tp_contact_list_get_all_groups (EmpathyContactList *list) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList *groups = NULL, *l; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); + GList *ret, *l; - if (priv->protocol_group) { - groups = g_list_prepend (groups, g_strdup (priv->protocol_group)); + ret = g_hash_table_get_keys (priv->groups); + for (l = ret; l; l = l->next) { + l->data = g_strdup (l->data); } - for (l = priv->groups; l; l = l->next) { - const gchar *name; - - name = empathy_tp_group_get_name (l->data); - groups = g_list_prepend (groups, g_strdup (name)); + if (priv->protocol_group) { + ret = g_list_prepend (ret, g_strdup (priv->protocol_group)); } - return groups; + return ret; } static GList * @@ -919,174 +929,119 @@ tp_contact_list_get_groups (EmpathyContactList *list, EmpathyContact *contact) { EmpathyTpContactListPriv *priv = GET_PRIV (list); - GList **groups; - GList *ret = NULL, *l; - - g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL); + GList *ret = NULL; + GHashTableIter iter; + gpointer group_name; + gpointer channel; + TpHandle handle; + + handle = empathy_contact_get_handle (contact); + g_hash_table_iter_init (&iter, priv->groups); + while (g_hash_table_iter_next (&iter, &group_name, &channel)) { + const TpIntSet *members; + + members = tp_channel_group_get_members (channel); + if (tp_intset_is_member (members, handle)) { + ret = g_list_prepend (ret, g_strdup (group_name)); + } + } if (priv->protocol_group) { ret = g_list_prepend (ret, g_strdup (priv->protocol_group)); } - groups = g_hash_table_lookup (priv->contacts_groups, contact); - if (!groups) { - return ret; - } - - for (l = *groups; l; l = l->next) { - ret = g_list_prepend (ret, g_strdup (l->data)); - } - - return ret; } -static EmpathyTpGroup * -tp_contact_list_get_group (EmpathyTpContactList *list, - const gchar *group) -{ - EmpathyTpContactListPriv *priv = GET_PRIV (list); - EmpathyTpGroup *tp_group; - gchar *object_path; - guint handle; - GArray *handles; - const char *names[2] = {group, NULL}; - GError *error = NULL; - - tp_group = tp_contact_list_find_group (list, group); - if (tp_group) { - return tp_group; - } - - DEBUG ("creating new group: %s", group); - - if (!tp_cli_connection_run_request_handles (priv->connection, -1, - TP_HANDLE_TYPE_GROUP, - names, - &handles, - &error, NULL)) { - DEBUG ("Failed to RequestHandles: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - return NULL; - } - handle = g_array_index (handles, guint, 0); - g_array_free (handles, TRUE); - - if (!tp_cli_connection_run_request_channel (priv->connection, -1, - TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, - TP_HANDLE_TYPE_GROUP, - handle, - TRUE, - &object_path, - &error, NULL)) { - DEBUG ("Failed to RequestChannel: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - return NULL; - } - - tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list), - object_path, - TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, - TP_HANDLE_TYPE_GROUP, handle); - - g_free (object_path); - - return tp_contact_list_find_group (list, group); -} - static void tp_contact_list_add_to_group (EmpathyContactList *list, EmpathyContact *contact, - const gchar *group) + const gchar *group_name) { - EmpathyTpGroup *tp_group; - - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); - - tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list), - group); - - if (tp_group) { - empathy_tp_group_add_member (tp_group, contact, ""); - } + TpHandle handle; + GArray *handles; + + handle = empathy_contact_get_handle (contact); + handles = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), 1); + g_array_append_val (handles, handle); + tp_contact_list_group_add (EMPATHY_TP_CONTACT_LIST (list), + group_name, handles); } static void tp_contact_list_remove_from_group (EmpathyContactList *list, EmpathyContact *contact, - const gchar *group) + const gchar *group_name) { - EmpathyTpGroup *tp_group; + EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpChannel *channel; + TpHandle handle; + GArray handles = {(gchar *) &handle, 1}; - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); + channel = g_hash_table_lookup (priv->groups, group_name); + if (channel == NULL) { + return; + } - tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list), - group); + handle = empathy_contact_get_handle (contact); + DEBUG ("remove contact %s (%d) from group %s", + empathy_contact_get_id (contact), handle, group_name); - if (tp_group) { - empathy_tp_group_remove_member (tp_group, contact, ""); - } + tp_cli_channel_interface_group_call_remove_members (channel, -1, + &handles, NULL, NULL, NULL, NULL, NULL); } static void tp_contact_list_rename_group (EmpathyContactList *list, - const gchar *old_group, - const gchar *new_group) + const gchar *old_group_name, + const gchar *new_group_name) { - EmpathyTpGroup *tp_group; - GList *members; - - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); + EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpChannel *channel; + const TpIntSet *members; + GArray *handles; - tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list), - old_group); - if (!tp_group) { + channel = g_hash_table_lookup (priv->groups, old_group_name); + if (channel == NULL) { return; } - DEBUG ("rename group %s to %s", old_group, new_group); - - /* Remove all members from the old group */ - members = empathy_tp_group_get_members (tp_group); - empathy_tp_group_remove_members (tp_group, members, ""); - empathy_tp_group_close (tp_group); + DEBUG ("rename group %s to %s", old_group_name, new_group_name); - /* Add all members to the new group */ - tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list), - new_group); - empathy_tp_group_add_members (tp_group, members, ""); + /* Remove all members and close the old channel */ + members = tp_channel_group_get_members (channel); + handles = tp_intset_to_array (members); + tp_cli_channel_interface_group_call_remove_members (channel, -1, + handles, NULL, NULL, NULL, NULL, NULL); + tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL); - g_list_foreach (members, (GFunc) g_object_unref, NULL); - g_list_free (members); + tp_contact_list_group_add (EMPATHY_TP_CONTACT_LIST (list), + new_group_name, handles); } static void tp_contact_list_remove_group (EmpathyContactList *list, - const gchar *group) + const gchar *group_name) { - EmpathyTpGroup *tp_group; - GList *members; - - g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); + EmpathyTpContactListPriv *priv = GET_PRIV (list); + TpChannel *channel; + const TpIntSet *members; + GArray *handles; - tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list), - group); - - if (!tp_group) { + channel = g_hash_table_lookup (priv->groups, group_name); + if (channel == NULL) { return; } - DEBUG ("remove group %s", group); + DEBUG ("remove group %s", group_name); - /* Remove all members of the group */ - members = empathy_tp_group_get_members (tp_group); - empathy_tp_group_remove_members (tp_group, members, ""); - empathy_tp_group_close (tp_group); - - g_list_foreach (members, (GFunc) g_object_unref, NULL); - g_list_free (members); + /* Remove all members and close the channel */ + members = tp_channel_group_get_members (channel); + handles = tp_intset_to_array (members); + tp_cli_channel_interface_group_call_remove_members (channel, -1, + handles, NULL, NULL, NULL, NULL, NULL); + tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL); + g_array_free (handles, TRUE); } static void @@ -1117,6 +1072,34 @@ empathy_tp_contact_list_can_add (EmpathyTpContactList *list) if (priv->subscribe == NULL) return FALSE; - flags = empathy_tp_group_get_flags (priv->subscribe); + flags = tp_channel_group_get_flags (priv->subscribe); return (flags & TP_CHANNEL_GROUP_FLAG_CAN_ADD) != 0; } + +void +empathy_tp_contact_list_remove_all (EmpathyTpContactList *list) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (list); + GHashTableIter iter; + gpointer contact; + + g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list)); + + /* Remove all contacts */ + g_hash_table_iter_init (&iter, priv->members); + while (g_hash_table_iter_next (&iter, NULL, &contact)) { + g_signal_emit_by_name (list, "members-changed", contact, + NULL, 0, NULL, + FALSE); + } + g_hash_table_remove_all (priv->members); + + g_hash_table_iter_init (&iter, priv->pendings); + while (g_hash_table_iter_next (&iter, NULL, &contact)) { + g_signal_emit_by_name (list, "pendings-changed", contact, + NULL, 0, NULL, + FALSE); + } + g_hash_table_remove_all (priv->pendings); +} + diff --git a/libempathy/empathy-tp-contact-list.h b/libempathy/empathy-tp-contact-list.h index e8edcface..c6cf6cb4a 100644 --- a/libempathy/empathy-tp-contact-list.h +++ b/libempathy/empathy-tp-contact-list.h @@ -24,7 +24,7 @@ #define __EMPATHY_TP_CONTACT_LIST_H__ #include <glib.h> -#include <libmissioncontrol/mc-account.h> +#include <telepathy-glib/connection.h> G_BEGIN_DECLS @@ -49,9 +49,10 @@ struct _EmpathyTpContactListClass { }; GType empathy_tp_contact_list_get_type (void) G_GNUC_CONST; -EmpathyTpContactList * empathy_tp_contact_list_new (McAccount *account); -McAccount * empathy_tp_contact_list_get_account (EmpathyTpContactList *list); +EmpathyTpContactList * empathy_tp_contact_list_new (TpConnection *connection); +TpConnection * empathy_tp_contact_list_get_connection (EmpathyTpContactList *list); gboolean empathy_tp_contact_list_can_add (EmpathyTpContactList *list); +void empathy_tp_contact_list_remove_all (EmpathyTpContactList *list); G_END_DECLS diff --git a/libempathy/empathy-tp-file.c b/libempathy/empathy-tp-file.c index 1f6bedfb2..6796f5a0b 100644 --- a/libempathy/empathy-tp-file.c +++ b/libempathy/empathy-tp-file.c @@ -39,7 +39,7 @@ #include <telepathy-glib/util.h> #include "empathy-tp-file.h" -#include "empathy-contact-factory.h" +#include "empathy-tp-contact-factory.h" #include "empathy-marshal.h" #include "empathy-time.h" #include "empathy-utils.h" @@ -277,9 +277,10 @@ copy_stream (GInputStream *in, /* EmpathyTpFile object */ struct _EmpathyTpFilePriv { - EmpathyContactFactory *factory; + EmpathyTpContactFactory *factory; MissionControl *mc; TpChannel *channel; + gboolean ready; EmpathyContact *contact; GInputStream *in_stream; @@ -307,6 +308,7 @@ enum { PROP_CHANNEL, PROP_STATE, PROP_INCOMING, + PROP_READY, PROP_FILENAME, PROP_SIZE, PROP_CONTENT_TYPE, @@ -493,81 +495,154 @@ tp_file_transferred_bytes_changed_cb (TpChannel *channel, g_object_notify (G_OBJECT (tp_file), "transferred-bytes"); } -static GObject * -tp_file_constructor (GType type, - guint n_props, - GObjectConstructParam *props) +static void +tp_file_check_if_ready (EmpathyTpFile *tp_file) { - GObject *file_obj; - EmpathyTpFile *tp_file; - TpHandle handle; - GHashTable *properties; - McAccount *account; - GValue *requested; - - file_obj = G_OBJECT_CLASS (empathy_tp_file_parent_class)->constructor (type, - n_props, props); - - tp_file = EMPATHY_TP_FILE (file_obj); - - tp_file->priv->factory = empathy_contact_factory_dup_singleton (); - tp_file->priv->mc = empathy_mission_control_dup_singleton (); - - g_signal_connect (tp_file->priv->channel, "invalidated", - G_CALLBACK (tp_file_invalidated_cb), tp_file); + if (tp_file->priv->ready || tp_file->priv->contact == NULL || + tp_file->priv->state == 0) + return; - tp_cli_channel_type_file_transfer_connect_to_file_transfer_state_changed ( - tp_file->priv->channel, tp_file_state_changed_cb, NULL, NULL, - G_OBJECT (tp_file), NULL); + tp_file->priv->ready = TRUE; + g_object_notify (G_OBJECT (tp_file), "ready"); +} - tp_cli_channel_type_file_transfer_connect_to_transferred_bytes_changed ( - tp_file->priv->channel, tp_file_transferred_bytes_changed_cb, - NULL, NULL, G_OBJECT (tp_file), NULL); +static void +tp_file_got_contact_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + EmpathyTpFile *tp_file = EMPATHY_TP_FILE (weak_object); - account = empathy_channel_get_account (tp_file->priv->channel); + if (error) + { + DEBUG ("Error: %s", error->message); + empathy_tp_file_close (tp_file); + return; + } - handle = tp_channel_get_handle (tp_file->priv->channel, NULL); - tp_file->priv->contact = empathy_contact_factory_get_from_handle ( - tp_file->priv->factory, account, (guint) handle); + tp_file->priv->contact = g_object_ref (contact); + tp_file_check_if_ready (tp_file); +} - tp_cli_dbus_properties_run_get_all (tp_file->priv->channel, - -1, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, &properties, NULL, NULL); +static void +tp_file_get_all_cb (TpProxy *proxy, + GHashTable *properties, + const GError *error, + gpointer user_data, + GObject *file_obj) +{ + EmpathyTpFile *tp_file = EMPATHY_TP_FILE (file_obj); - tp_cli_dbus_properties_run_get (tp_file->priv->channel, - -1, TP_IFACE_CHANNEL, "Requested", &requested, NULL, NULL); + if (error) + { + DEBUG ("Error: %s", error->message); + tp_cli_channel_call_close (tp_file->priv->channel, -1, NULL, NULL, NULL, + NULL); + return; + } tp_file->priv->size = g_value_get_uint64 ( g_hash_table_lookup (properties, "Size")); + g_object_notify (file_obj, "size"); tp_file->priv->state = g_value_get_uint ( g_hash_table_lookup (properties, "State")); - - tp_file->priv->state_change_reason = - TP_FILE_TRANSFER_STATE_CHANGE_REASON_NONE; + g_object_notify (file_obj, "state"); tp_file->priv->transferred_bytes = g_value_get_uint64 ( g_hash_table_lookup (properties, "TransferredBytes")); + g_object_notify (file_obj, "transferred-bytes"); tp_file->priv->filename = g_value_dup_string ( g_hash_table_lookup (properties, "Filename")); + g_object_notify (file_obj, "filename"); tp_file->priv->content_hash = g_value_dup_string ( g_hash_table_lookup (properties, "ContentHash")); + g_object_notify (file_obj, "content-hash"); tp_file->priv->content_hash_type = g_value_get_uint ( g_hash_table_lookup (properties, "ContentHashType")); + g_object_notify (file_obj, "content-hash-type"); tp_file->priv->content_type = g_value_dup_string ( g_hash_table_lookup (properties, "ContentType")); + g_object_notify (file_obj, "content-type"); tp_file->priv->description = g_value_dup_string ( g_hash_table_lookup (properties, "Description")); + tp_file_check_if_ready (tp_file); +} + +static void +tp_file_get_requested_cb (TpProxy *proxy, + const GValue *requested, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + EmpathyTpFile *tp_file = EMPATHY_TP_FILE (weak_object); + + if (error) + { + DEBUG ("Error: %s", error->message); + tp_cli_channel_call_close (tp_file->priv->channel, -1, NULL, NULL, NULL, + NULL); + return; + } + tp_file->priv->incoming = !g_value_get_boolean (requested); + g_object_notify (G_OBJECT (tp_file), "incoming"); + + tp_file_check_if_ready (tp_file); +} + +static GObject * +tp_file_constructor (GType type, + guint n_props, + GObjectConstructParam *props) +{ + GObject *file_obj; + EmpathyTpFile *tp_file; + TpHandle handle; + TpConnection *connection; + + file_obj = G_OBJECT_CLASS (empathy_tp_file_parent_class)->constructor (type, + n_props, props); + + tp_file = EMPATHY_TP_FILE (file_obj); + + connection = tp_channel_borrow_connection (tp_file->priv->channel); + tp_file->priv->factory = empathy_tp_contact_factory_dup_singleton (connection); + tp_file->priv->mc = empathy_mission_control_dup_singleton (); + tp_file->priv->state_change_reason = + TP_FILE_TRANSFER_STATE_CHANGE_REASON_NONE; + + g_signal_connect (tp_file->priv->channel, "invalidated", + G_CALLBACK (tp_file_invalidated_cb), tp_file); + + tp_cli_channel_type_file_transfer_connect_to_file_transfer_state_changed ( + tp_file->priv->channel, tp_file_state_changed_cb, NULL, NULL, + G_OBJECT (tp_file), NULL); + + tp_cli_channel_type_file_transfer_connect_to_transferred_bytes_changed ( + tp_file->priv->channel, tp_file_transferred_bytes_changed_cb, + NULL, NULL, G_OBJECT (tp_file), NULL); - g_hash_table_destroy (properties); - g_object_unref (account); - g_value_unset (requested); + tp_cli_dbus_properties_call_get (tp_file->priv->channel, -1, + TP_IFACE_CHANNEL, "Requested", + tp_file_get_requested_cb, NULL, NULL, file_obj); + + tp_cli_dbus_properties_call_get_all (tp_file->priv->channel, -1, + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, + tp_file_get_all_cb, NULL, NULL, file_obj); + + handle = tp_channel_get_handle (tp_file->priv->channel, NULL); + empathy_tp_contact_factory_get_from_handle (tp_file->priv->factory, + handle, tp_file_got_contact_cb, NULL, NULL, file_obj); return file_obj; } @@ -611,6 +686,9 @@ tp_file_get_property (GObject *object, case PROP_TRANSFERRED_BYTES: g_value_set_uint64 (value, tp_file->priv->transferred_bytes); break; + case PROP_READY: + g_value_set_boolean (value, tp_file->priv->ready); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; @@ -956,6 +1034,14 @@ empathy_tp_file_close (EmpathyTpFile *tp_file) empathy_tp_file_cancel (tp_file); } +gboolean +empathy_tp_file_is_ready (EmpathyTpFile *tp_file) +{ + g_return_val_if_fail (EMPATHY_IS_TP_FILE (tp_file), FALSE); + + return tp_file->priv->ready; +} + static void empathy_tp_file_class_init (EmpathyTpFileClass *klass) { @@ -997,6 +1083,14 @@ empathy_tp_file_class_init (EmpathyTpFileClass *klass) G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, + PROP_READY, + g_param_spec_boolean ("ready", + "ready", + "Whether the object is ready", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, PROP_FILENAME, g_param_spec_string ("filename", "name of the transfer", diff --git a/libempathy/empathy-tp-file.h b/libempathy/empathy-tp-file.h index 42c54e4f0..5f239c8e0 100644 --- a/libempathy/empathy-tp-file.h +++ b/libempathy/empathy-tp-file.h @@ -81,6 +81,7 @@ guint64 empathy_tp_file_get_size (EmpathyTpFile *tp_file); guint64 empathy_tp_file_get_transferred_bytes (EmpathyTpFile *tp_file); gint empathy_tp_file_get_remaining_time (EmpathyTpFile *tp_file); const gchar *empathy_tp_file_get_content_type (EmpathyTpFile *tp_file); +gboolean empathy_tp_file_is_ready (EmpathyTpFile *tp_file); G_END_DECLS diff --git a/libempathy/empathy-tp-group.c b/libempathy/empathy-tp-group.c deleted file mode 100644 index c3471c157..000000000 --- a/libempathy/empathy-tp-group.c +++ /dev/null @@ -1,981 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006 Xavier Claessens <xclaesse@gmail.com> - * Copyright (C) 2007-2008 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: Xavier Claessens <xclaesse@gmail.com> - */ - -#include <config.h> - -#include <libmissioncontrol/mc-account.h> - -#include <telepathy-glib/util.h> -#include <telepathy-glib/interfaces.h> - -#include "empathy-tp-group.h" -#include "empathy-contact-factory.h" -#include "empathy-utils.h" -#include "empathy-marshal.h" - -#define DEBUG_FLAG EMPATHY_DEBUG_TP -#include "empathy-debug.h" - -#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpGroup) -typedef struct { - TpChannel *channel; - gboolean ready; - - EmpathyContactFactory *factory; - McAccount *account; - gchar *group_name; - guint self_handle; - GList *members; - GList *local_pendings; - GList *remote_pendings; -} EmpathyTpGroupPriv; - -enum { - MEMBER_ADDED, - MEMBER_REMOVED, - LOCAL_PENDING, - REMOTE_PENDING, - DESTROY, - LAST_SIGNAL -}; - -enum { - PROP_0, - PROP_CHANNEL, - PROP_READY -}; - -static guint signals[LAST_SIGNAL]; - -G_DEFINE_TYPE (EmpathyTpGroup, empathy_tp_group, G_TYPE_OBJECT); - -static EmpathyContact * -tp_group_get_contact (EmpathyTpGroup *group, - guint handle) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyContact *contact = NULL; - - if (handle != 0) { - contact = empathy_contact_factory_get_from_handle (priv->factory, - priv->account, - handle); - } - - if (contact && handle == priv->self_handle) { - empathy_contact_set_is_user (contact, TRUE); - } - - return contact; -} - -static GList * -tp_group_get_contacts (EmpathyTpGroup *group, - const GArray *handles) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GList *contacts, *l; - - if (!handles) { - return NULL; - } - - contacts = empathy_contact_factory_get_from_handles (priv->factory, - priv->account, - handles); - - /* FIXME: Only useful if the group has a different self handle than - * the connection, otherwise the contact factory already set that - * property. That can be known using group flags. */ - for (l = contacts; l; l = l->next) { - if (empathy_contact_get_handle (l->data) == priv->self_handle) { - empathy_contact_set_is_user (l->data, TRUE); - } - } - - return contacts; -} - -EmpathyPendingInfo * -empathy_pending_info_new (EmpathyContact *member, - EmpathyContact *actor, - const gchar *message) -{ - EmpathyPendingInfo *info; - - info = g_slice_new0 (EmpathyPendingInfo); - - if (member) { - info->member = g_object_ref (member); - } - if (actor) { - info->actor = g_object_ref (actor); - } - if (message) { - info->message = g_strdup (message); - } - - return info; -} - -void -empathy_pending_info_free (EmpathyPendingInfo *info) -{ - if (!info) { - return; - } - - if (info->member) { - g_object_unref (info->member); - } - if (info->actor) { - g_object_unref (info->actor); - } - g_free (info->message); - - g_slice_free (EmpathyPendingInfo, info); -} - -static gint -tp_group_local_pending_find (gconstpointer a, - gconstpointer b) -{ - const EmpathyPendingInfo *info = a; - - return (info->member != b); -} - -static void -tp_group_remove_from_pendings (EmpathyTpGroup *group, - EmpathyContact *contact) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GList *l; - - /* local pending */ - l = g_list_find_custom (priv->local_pendings, - contact, - tp_group_local_pending_find); - if (l) { - empathy_pending_info_free (l->data); - priv->local_pendings = g_list_delete_link (priv->local_pendings, l); - } - - /* remote pending */ - l = g_list_find (priv->remote_pendings, contact); - if (l) { - g_object_unref (l->data); - priv->remote_pendings = g_list_delete_link (priv->remote_pendings, l); - } -} - -static void -tp_group_update_members (EmpathyTpGroup *group, - const gchar *message, - const GArray *added, - const GArray *removed, - const GArray *local_pending, - const GArray *remote_pending, - guint actor, - guint reason) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyContact *actor_contact = NULL; - GList *contacts, *l, *ll; - - actor_contact = tp_group_get_contact (group, actor); - - DEBUG ("Members changed for list %s:\n" - " added-len=%d, current-len=%d\n" - " removed-len=%d\n" - " local-pending-len=%d, current-len=%d\n" - " remote-pending-len=%d, current-len=%d", - priv->group_name, added ? added->len : 0, - g_list_length (priv->members), removed ? removed->len : 0, - local_pending ? local_pending->len : 0, - g_list_length (priv->local_pendings), - remote_pending ? remote_pending->len : 0, - g_list_length (priv->remote_pendings)); - - /* Contacts added */ - contacts = tp_group_get_contacts (group, added); - for (l = contacts; l; l = l->next) { - tp_group_remove_from_pendings (group, l->data); - - /* If the contact is not yet member, add it and emit signal */ - if (!g_list_find (priv->members, l->data)) { - priv->members = g_list_prepend (priv->members, - g_object_ref (l->data)); - g_signal_emit (group, signals[MEMBER_ADDED], 0, - l->data, actor_contact, reason, message); - } - g_object_unref (l->data); - } - g_list_free (contacts); - - /* Contacts removed */ - contacts = tp_group_get_contacts (group, removed); - for (l = contacts; l; l = l->next) { - tp_group_remove_from_pendings (group, l->data); - - /* If the contact is member, remove it and emit signal */ - if ((ll = g_list_find (priv->members, l->data))) { - g_object_unref (ll->data); - priv->members = g_list_delete_link (priv->members, ll); - g_signal_emit (group, signals[MEMBER_REMOVED], 0, - l->data, actor_contact, reason, message); - } - g_object_unref (l->data); - } - g_list_free (contacts); - - /* Contacts local pending */ - contacts = tp_group_get_contacts (group, local_pending); - for (l = contacts; l; l = l->next) { - /* If the contact is not yet local-pending, add it and emit signal */ - if (!g_list_find_custom (priv->local_pendings, l->data, - tp_group_local_pending_find)) { - EmpathyPendingInfo *info; - - info = empathy_pending_info_new (l->data, - actor_contact, - message); - - priv->local_pendings = g_list_prepend (priv->local_pendings, info); - g_signal_emit (group, signals[LOCAL_PENDING], 0, - l->data, actor_contact, reason, message); - } - g_object_unref (l->data); - } - g_list_free (contacts); - - /* Contacts remote pending */ - contacts = tp_group_get_contacts (group, remote_pending); - for (l = contacts; l; l = l->next) { - /* If the contact is not yet remote-pending, add it and emit signal */ - if (!g_list_find (priv->remote_pendings, l->data)) { - priv->remote_pendings = g_list_prepend (priv->remote_pendings, - g_object_ref (l->data)); - g_signal_emit (group, signals[REMOTE_PENDING], 0, - l->data, actor_contact, reason, message); - } - g_object_unref (l->data); - } - g_list_free (contacts); - - if (actor_contact) { - g_object_unref (actor_contact); - } - - DEBUG ("Members changed done for list %s:\n" - " members-len=%d\n" - " local-pendings-len=%d\n" - " remote-pendings-len=%d", - priv->group_name, g_list_length (priv->members), - g_list_length (priv->local_pendings), - g_list_length (priv->remote_pendings)); -} - -static void -tp_group_members_changed_cb (TpChannel *channel, - const gchar *message, - const GArray *added, - const GArray *removed, - const GArray *local_pending, - const GArray *remote_pending, - guint actor, - guint reason, - gpointer user_data, - GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - if (priv->ready) { - tp_group_update_members (EMPATHY_TP_GROUP (group), message, - added, removed, - local_pending, remote_pending, - actor, reason); - } -} - -static void -tp_group_get_members_cb (TpChannel *channel, - const GArray *handles, - const GError *error, - gpointer user_data, - GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - if (error) { - DEBUG ("Failed to get members: %s", error->message); - return; - } - - tp_group_update_members (EMPATHY_TP_GROUP (group), - NULL, /* message */ - handles, /* added */ - NULL, /* removed */ - NULL, /* local_pending */ - NULL, /* remote_pending */ - 0, /* actor */ - 0); /* reason */ - - DEBUG ("Ready"); - priv->ready = TRUE; - g_object_notify (group, "ready"); -} - -static void -tp_group_get_local_pending_cb (TpChannel *channel, - const GPtrArray *array, - const GError *error, - gpointer user_data, - GObject *group) -{ - GArray *handles; - guint i = 0; - - if (error) { - DEBUG ("Failed to get local pendings: %s", error->message); - return; - } - - handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); - g_array_append_val (handles, i); - for (i = 0; array->len > i; i++) { - GValueArray *pending_struct; - const gchar *message; - guint member_handle; - guint actor_handle; - guint reason; - - pending_struct = g_ptr_array_index (array, i); - member_handle = g_value_get_uint (g_value_array_get_nth (pending_struct, 0)); - actor_handle = g_value_get_uint (g_value_array_get_nth (pending_struct, 1)); - reason = g_value_get_uint (g_value_array_get_nth (pending_struct, 2)); - message = g_value_get_string (g_value_array_get_nth (pending_struct, 3)); - - g_array_index (handles, guint, 0) = member_handle; - - tp_group_update_members (EMPATHY_TP_GROUP (group), - message, /* message */ - NULL, /* added */ - NULL, /* removed */ - handles, /* local_pending */ - NULL, /* remote_pending */ - actor_handle, /* actor */ - reason); /* reason */ - } - g_array_free (handles, TRUE); -} - -static void -tp_group_get_remote_pending_cb (TpChannel *channel, - const GArray *handles, - const GError *error, - gpointer user_data, - GObject *group) -{ - if (error) { - DEBUG ("Failed to get remote pendings: %s", error->message); - return; - } - - tp_group_update_members (EMPATHY_TP_GROUP (group), - NULL, /* message */ - NULL, /* added */ - NULL, /* removed */ - NULL, /* local_pending */ - handles, /* remote_pending */ - 0, /* actor */ - 0); /* reason */ -} - -static void -tp_group_inspect_handles_cb (TpConnection *connection, - const gchar **names, - const GError *error, - gpointer user_data, - GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - if (error) { - DEBUG ("Failed to inspect channel handle: %s", error->message); - return; - } - - priv->group_name = g_strdup (*names); -} - -static void -tp_group_invalidated_cb (TpProxy *proxy, - guint domain, - gint code, - gchar *message, - EmpathyTpGroup *group) -{ - DEBUG ("Channel invalidated: %s", message); - g_signal_emit (group, signals[DESTROY], 0); -} - -static void -tp_group_get_self_handle_cb (TpChannel *proxy, - guint handle, - const GError *error, - gpointer user_data, - GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - TpConnection *connection; - guint channel_handle; - guint channel_handle_type; - GArray *handles; - - if (error) { - DEBUG ("Failed to get self handle: %s", error->message); - return; - } - - priv->self_handle = handle; - tp_cli_channel_interface_group_connect_to_members_changed (priv->channel, - tp_group_members_changed_cb, - NULL, NULL, - group, NULL); - - /* GetMembers is called last, so it will be the last to get the reply, - * so we'll be ready once that call return. */ - g_object_get (priv->channel, - "connection", &connection, - "handle-type", &channel_handle_type, - "handle", &channel_handle, - NULL); - handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); - g_array_prepend_val (handles, channel_handle); - tp_cli_connection_call_inspect_handles (connection, -1, - channel_handle_type, - handles, - tp_group_inspect_handles_cb, - NULL, NULL, - group); - g_array_free (handles, TRUE); - - tp_cli_channel_interface_group_call_get_local_pending_members_with_info - (priv->channel, -1, - tp_group_get_local_pending_cb, - NULL, NULL, - group); - tp_cli_channel_interface_group_call_get_remote_pending_members - (priv->channel, -1, - tp_group_get_remote_pending_cb, - NULL, NULL, - group); - tp_cli_channel_interface_group_call_get_members (priv->channel, -1, - tp_group_get_members_cb, - NULL, NULL, - group); -} - -static void -tp_group_factory_ready_cb (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (priv->factory, priv->account); - g_signal_handlers_disconnect_by_func (tp_factory, tp_group_factory_ready_cb, group); - tp_cli_channel_interface_group_call_get_self_handle (priv->channel, -1, - tp_group_get_self_handle_cb, - NULL, NULL, - G_OBJECT (group)); -} - -static void -tp_group_channel_ready_cb (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyTpContactFactory *tp_factory; - - tp_factory = empathy_contact_factory_get_tp_factory (priv->factory, - priv->account); - if (empathy_tp_contact_factory_is_ready (tp_factory)) { - tp_group_factory_ready_cb (group); - } else { - g_signal_connect_swapped (tp_factory, "notify::ready", - G_CALLBACK (tp_group_factory_ready_cb), - group); - } -} - -static void -tp_group_finalize (GObject *object) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (object); - EmpathyTpContactFactory *tp_factory; - - DEBUG ("finalize: %p", object); - - tp_factory = empathy_contact_factory_get_tp_factory (priv->factory, priv->account); - g_signal_handlers_disconnect_by_func (tp_factory, tp_group_factory_ready_cb, object); - - if (priv->channel) { - g_signal_handlers_disconnect_by_func (priv->channel, - tp_group_invalidated_cb, - object); - g_object_unref (priv->channel); - } - if (priv->account) { - g_object_unref (priv->account); - } - if (priv->factory) { - g_object_unref (priv->factory); - } - g_free (priv->group_name); - - g_list_foreach (priv->members, (GFunc) g_object_unref, NULL); - g_list_free (priv->members); - - g_list_foreach (priv->local_pendings, (GFunc) empathy_pending_info_free, NULL); - g_list_free (priv->local_pendings); - - g_list_foreach (priv->remote_pendings, (GFunc) g_object_unref, NULL); - g_list_free (priv->remote_pendings); - - G_OBJECT_CLASS (empathy_tp_group_parent_class)->finalize (object); -} - -static void -tp_group_constructed (GObject *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - gboolean channel_ready; - - priv->factory = empathy_contact_factory_dup_singleton (); - priv->account = empathy_channel_get_account (priv->channel); - - g_signal_connect (priv->channel, "invalidated", - G_CALLBACK (tp_group_invalidated_cb), - group); - - g_object_get (priv->channel, "channel-ready", &channel_ready, NULL); - if (channel_ready) { - tp_group_channel_ready_cb (EMPATHY_TP_GROUP (group)); - } else { - g_signal_connect_swapped (priv->channel, "notify::channel-ready", - G_CALLBACK (tp_group_channel_ready_cb), - group); - } -} - -static void -tp_group_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (object); - - switch (param_id) { - case PROP_CHANNEL: - g_value_set_object (value, priv->channel); - break; - case PROP_READY: - g_value_set_boolean (value, priv->ready); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -tp_group_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (object); - - switch (param_id) { - case PROP_CHANNEL: - priv->channel = g_object_ref (g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -empathy_tp_group_class_init (EmpathyTpGroupClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = tp_group_finalize; - object_class->constructed = tp_group_constructed; - object_class->get_property = tp_group_get_property; - object_class->set_property = tp_group_set_property; - - g_object_class_install_property (object_class, - PROP_CHANNEL, - g_param_spec_object ("channel", - "telepathy channel", - "The channel for the group", - TP_TYPE_CHANNEL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); - g_object_class_install_property (object_class, - PROP_READY, - g_param_spec_boolean ("ready", - "Is the object ready", - "This object can't be used until this becomes true", - FALSE, - G_PARAM_READABLE)); - - signals[MEMBER_ADDED] = - g_signal_new ("member-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, - G_TYPE_NONE, - 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); - - signals[MEMBER_REMOVED] = - g_signal_new ("member-removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, - G_TYPE_NONE, - 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); - - signals[LOCAL_PENDING] = - g_signal_new ("local-pending", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, - G_TYPE_NONE, - 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); - - signals[REMOTE_PENDING] = - g_signal_new ("remote-pending", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING, - G_TYPE_NONE, - 4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING); - - signals[DESTROY] = - g_signal_new ("destroy", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - g_type_class_add_private (object_class, sizeof (EmpathyTpGroupPriv)); -} - -static void -empathy_tp_group_init (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (group, - EMPATHY_TYPE_TP_GROUP, EmpathyTpGroupPriv); - - group->priv = priv; -} - -EmpathyTpGroup * -empathy_tp_group_new (TpChannel *channel) -{ - g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL); - - return g_object_new (EMPATHY_TYPE_TP_GROUP, - "channel", channel, - NULL); -} - -static void -tp_group_async_cb (TpChannel *channel, - const GError *error, - gpointer user_data, - GObject *weak_object) -{ - if (error) { - DEBUG ("%s: %s", (gchar*) user_data, error->message); - } -} - -void -empathy_tp_group_close (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); - g_return_if_fail (priv->ready); - - tp_cli_channel_call_close (priv->channel, -1, - tp_group_async_cb, - "Failed to close", NULL, - G_OBJECT (group)); -} - -static GArray * -tp_group_get_handles (GList *contacts) -{ - GArray *handles; - guint length; - GList *l; - - length = g_list_length (contacts); - handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), length); - - for (l = contacts; l; l = l->next) { - guint handle; - - handle = empathy_contact_get_handle (l->data); - g_array_append_val (handles, handle); - } - - return handles; -} - -void -empathy_tp_group_add_members (EmpathyTpGroup *group, - GList *contacts, - const gchar *message) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GArray *handles; - - g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); - g_return_if_fail (contacts != NULL); - g_return_if_fail (priv->ready); - - handles = tp_group_get_handles (contacts); - tp_cli_channel_interface_group_call_add_members (priv->channel, -1, - handles, - message, - tp_group_async_cb, - "Failed to add members", NULL, - G_OBJECT (group)); - g_array_free (handles, TRUE); -} - -void -empathy_tp_group_remove_members (EmpathyTpGroup *group, - GList *contacts, - const gchar *message) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GArray *handles; - - g_return_if_fail (EMPATHY_IS_TP_GROUP (group)); - g_return_if_fail (contacts != NULL); - g_return_if_fail (priv->ready); - - handles = tp_group_get_handles (contacts); - tp_cli_channel_interface_group_call_remove_members (priv->channel, -1, - handles, - message, - tp_group_async_cb, - "Failed to remove members", NULL, - G_OBJECT (group)); - g_array_free (handles, TRUE); -} - -void -empathy_tp_group_add_member (EmpathyTpGroup *group, - EmpathyContact *contact, - const gchar *message) -{ - GList *contacts; - - contacts = g_list_prepend (NULL, contact); - empathy_tp_group_add_members (group, contacts, message); - g_list_free (contacts); -} - -void -empathy_tp_group_remove_member (EmpathyTpGroup *group, - EmpathyContact *contact, - const gchar *message) -{ - GList *contacts; - - contacts = g_list_prepend (NULL, contact); - empathy_tp_group_remove_members (group, contacts, message); - g_list_free (contacts); -} - -GList * -empathy_tp_group_get_members (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - - g_list_foreach (priv->members, (GFunc) g_object_ref, NULL); - - return g_list_copy (priv->members); -} - -GList * -empathy_tp_group_get_local_pendings (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - GList *pendings = NULL, *l; - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - - for (l = priv->local_pendings; l; l = l->next) { - EmpathyPendingInfo *info; - EmpathyPendingInfo *new_info; - - info = l->data; - new_info = empathy_pending_info_new (info->member, - info->actor, - info->message); - pendings = g_list_prepend (pendings, new_info); - } - - return pendings; -} - -GList * -empathy_tp_group_get_remote_pendings (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - - g_list_foreach (priv->remote_pendings, (GFunc) g_object_ref, NULL); - - return g_list_copy (priv->remote_pendings); -} - -const gchar * -empathy_tp_group_get_name (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - g_return_val_if_fail (priv->ready, NULL); - - return priv->group_name; -} - -EmpathyContact * -empathy_tp_group_get_self_contact (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL); - g_return_val_if_fail (priv->ready, NULL); - - return tp_group_get_contact (group, priv->self_handle); -} - -gboolean -empathy_tp_group_is_member (EmpathyTpGroup *group, - EmpathyContact *contact) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), FALSE); - g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE); - - return g_list_find (priv->members, contact) != NULL; -} - -gboolean -empathy_tp_group_is_ready (EmpathyTpGroup *group) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), FALSE); - - return priv->ready; -} - -EmpathyPendingInfo * -empathy_tp_group_get_invitation (EmpathyTpGroup *group, - EmpathyContact **remote_contact) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (group); - EmpathyContact *contact = NULL; - EmpathyPendingInfo *invitation = NULL; - GList *l; - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), FALSE); - g_return_val_if_fail (priv->ready, NULL); - - for (l = priv->local_pendings; l; l = l->next) { - EmpathyPendingInfo *info = l->data; - - if (empathy_contact_is_user (info->member)) { - invitation = info; - break; - } - } - - if (invitation) { - contact = invitation->actor; - } - if (!invitation) { - if (priv->remote_pendings) { - contact = priv->remote_pendings->data; - } - else if (priv->members) { - contact = priv->members->data; - } - } - - if (remote_contact && contact) { - *remote_contact = g_object_ref (contact); - } - - return invitation; -} - -TpChannelGroupFlags -empathy_tp_group_get_flags (EmpathyTpGroup *self) -{ - EmpathyTpGroupPriv *priv = GET_PRIV (self); - - g_return_val_if_fail (EMPATHY_IS_TP_GROUP (self), 0); - - if (priv->channel == NULL) - return 0; - - return tp_channel_group_get_flags (priv->channel); -} diff --git a/libempathy/empathy-tp-group.h b/libempathy/empathy-tp-group.h deleted file mode 100644 index 9e0dd53ef..000000000 --- a/libempathy/empathy-tp-group.h +++ /dev/null @@ -1,93 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2006 Xavier Claessens <xclaesse@gmail.com> - * Copyright (C) 2007-2008 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: Xavier Claessens <xclaesse@gmail.com> - */ - -#ifndef __EMPATHY_TP_GROUP_H__ -#define __EMPATHY_TP_GROUP_H__ - -#include <glib.h> - -#include <telepathy-glib/channel.h> - -#include "empathy-contact.h" - -G_BEGIN_DECLS - -#define EMPATHY_TYPE_TP_GROUP (empathy_tp_group_get_type ()) -#define EMPATHY_TP_GROUP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_TP_GROUP, EmpathyTpGroup)) -#define EMPATHY_TP_GROUP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_TP_GROUP, EmpathyTpGroupClass)) -#define EMPATHY_IS_TP_GROUP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_TP_GROUP)) -#define EMPATHY_IS_TP_GROUP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_TP_GROUP)) -#define EMPATHY_TP_GROUP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_TP_GROUP, EmpathyTpGroupClass)) - -typedef struct _EmpathyTpGroup EmpathyTpGroup; -typedef struct _EmpathyTpGroupClass EmpathyTpGroupClass; - -struct _EmpathyTpGroup { - GObject parent; - gpointer priv; -}; - -struct _EmpathyTpGroupClass { - GObjectClass parent_class; -}; - -typedef struct { - EmpathyContact *member; - EmpathyContact *actor; - gchar *message; - guint reason; -} EmpathyPendingInfo; - -GType empathy_tp_group_get_type (void) G_GNUC_CONST; -EmpathyTpGroup * empathy_tp_group_new (TpChannel *channel); -void empathy_tp_group_close (EmpathyTpGroup *group); -void empathy_tp_group_add_members (EmpathyTpGroup *group, - GList *contacts, - const gchar *message); -void empathy_tp_group_add_member (EmpathyTpGroup *group, - EmpathyContact *contact, - const gchar *message); -void empathy_tp_group_remove_members (EmpathyTpGroup *group, - GList *contacts, - const gchar *message); -void empathy_tp_group_remove_member (EmpathyTpGroup *group, - EmpathyContact *contact, - const gchar *message); -GList * empathy_tp_group_get_members (EmpathyTpGroup *group); -GList * empathy_tp_group_get_local_pendings (EmpathyTpGroup *group); -GList * empathy_tp_group_get_remote_pendings (EmpathyTpGroup *group); -const gchar * empathy_tp_group_get_name (EmpathyTpGroup *group); -EmpathyContact * empathy_tp_group_get_self_contact (EmpathyTpGroup *group); -gboolean empathy_tp_group_is_member (EmpathyTpGroup *group, - EmpathyContact *contact); -gboolean empathy_tp_group_is_ready (EmpathyTpGroup *group); -EmpathyPendingInfo *empathy_tp_group_get_invitation (EmpathyTpGroup *group, - EmpathyContact **remote_contact); -EmpathyPendingInfo *empathy_pending_info_new (EmpathyContact *member, - EmpathyContact *actor, - const gchar *message); -void empathy_pending_info_free (EmpathyPendingInfo *info); -TpChannelGroupFlags empathy_tp_group_get_flags (EmpathyTpGroup *group); - -G_END_DECLS - -#endif /* __EMPATHY_TP_GROUP_H__ */ diff --git a/libempathy/empathy-tp-tube.c b/libempathy/empathy-tp-tube.c index 746708fc4..7d22f6b78 100644 --- a/libempathy/empathy-tp-tube.c +++ b/libempathy/empathy-tp-tube.c @@ -390,8 +390,6 @@ empathy_tp_tube_new_stream_tube (EmpathyContact *contact, const gchar *service, GHashTable *parameters) { - MissionControl *mc; - McAccount *account; TpConnection *connection; TpChannel *channel; gchar *object_path; @@ -408,12 +406,7 @@ empathy_tp_tube_new_stream_tube (EmpathyContact *contact, g_return_val_if_fail (hostname != NULL, NULL); g_return_val_if_fail (service != NULL, NULL); - mc = empathy_mission_control_dup_singleton (); - account = empathy_contact_get_account (contact); - connection = mission_control_get_tpconnection (mc, account, NULL); - g_object_unref (mc); - - tp_connection_run_until_ready (connection, FALSE, NULL, NULL); + connection = empathy_contact_get_connection (contact); request = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free); diff --git a/libempathy/empathy-utils.c b/libempathy/empathy-utils.c index a476d9e54..210c35048 100644 --- a/libempathy/empathy-utils.c +++ b/libempathy/empathy-utils.c @@ -37,7 +37,6 @@ #include <telepathy-glib/dbus.h> #include "empathy-utils.h" -#include "empathy-contact-factory.h" #include "empathy-contact-manager.h" #include "empathy-dispatcher.h" #include "empathy-dispatch-operation.h" @@ -332,97 +331,6 @@ empathy_file_lookup (const gchar *filename, const gchar *subdir) return path; } -typedef struct { - EmpathyRunUntilReadyFunc func; - gpointer user_data; - GObject *object; - GMainLoop *loop; -} RunUntilReadyData; - -static void -run_until_ready_cb (RunUntilReadyData *data) -{ - if (!data->func || data->func (data->object, data->user_data)) { - DEBUG ("Object %p is ready", data->object); - g_main_loop_quit (data->loop); - } -} - -static gboolean -object_is_ready (GObject *object, - gpointer user_data) -{ - gboolean ready; - - g_object_get (object, "ready", &ready, NULL); - - return ready; -} - -void -empathy_run_until_ready_full (gpointer object, - const gchar *signal, - EmpathyRunUntilReadyFunc func, - gpointer user_data, - GMainLoop **loop) -{ - RunUntilReadyData data; - gulong signal_id; - - g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (signal != NULL); - - if (func && func (object, user_data)) { - return; - } - - DEBUG ("Starting run until ready for object %p", object); - - data.func = func; - data.user_data = user_data; - data.object = object; - data.loop = g_main_loop_new (NULL, FALSE); - - signal_id = g_signal_connect_swapped (object, signal, - G_CALLBACK (run_until_ready_cb), - &data); - if (loop != NULL) { - *loop = data.loop; - } - - g_main_loop_run (data.loop); - - if (loop != NULL) { - *loop = NULL; - } - - g_signal_handler_disconnect (object, signal_id); - g_main_loop_unref (data.loop); -} - -void -empathy_run_until_ready (gpointer object) -{ - empathy_run_until_ready_full (object, "notify::ready", object_is_ready, - NULL, NULL); -} - -McAccount * -empathy_channel_get_account (TpChannel *channel) -{ - TpConnection *connection; - McAccount *account; - MissionControl *mc; - - g_object_get (channel, "connection", &connection, NULL); - mc = empathy_mission_control_dup_singleton (); - account = mission_control_get_account_for_tpconnection (mc, connection, NULL); - g_object_unref (connection); - g_object_unref (mc); - - return account; -} - guint empathy_proxy_hash (gconstpointer key) { @@ -470,3 +378,4 @@ empathy_check_available_state (void) return TRUE; } + diff --git a/libempathy/empathy-utils.h b/libempathy/empathy-utils.h index 8684acc00..e6bcfebfc 100644 --- a/libempathy/empathy-utils.h +++ b/libempathy/empathy-utils.h @@ -74,16 +74,6 @@ const gchar * empathy_presence_to_str (McPresence presence); McPresence empathy_presence_from_str (const gchar *str); gchar * empathy_file_lookup (const gchar *filename, const gchar *subdir); - -typedef gboolean (*EmpathyRunUntilReadyFunc) (GObject *object, - gpointer user_data); -void empathy_run_until_ready (gpointer object); -void empathy_run_until_ready_full (gpointer object, - const gchar *signal, - EmpathyRunUntilReadyFunc func, - gpointer user_data, - GMainLoop **loop); -McAccount * empathy_channel_get_account (TpChannel *channel); gboolean empathy_proxy_equal (gconstpointer a, gconstpointer b); guint empathy_proxy_hash (gconstpointer key); |