1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007 Xavier Claessens <xclaesse@gmail.com>
4 * Copyright (C) 2007 Collabora Ltd.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * Authors: Xavier Claessens <xclaesse@gmail.com>
26 #include <glib/gi18n.h>
28 #include <libtelepathy/tp-helpers.h>
29 #include <libtelepathy/tp-conn.h>
30 #include <libtelepathy/tp-chan.h>
31 #include <libtelepathy/tp-chan-type-contact-list-gen.h>
33 #include "empathy-tp-contact-list.h"
34 #include "empathy-contact-list.h"
35 #include "empathy-tp-group.h"
36 #include "empathy-debug.h"
37 #include "empathy-utils.h"
39 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
40 EMPATHY_TYPE_TP_CONTACT_LIST, EmpathyTpContactListPriv))
42 #define DEBUG_DOMAIN "TpContactList"
44 struct _EmpathyTpContactListPriv {
48 const gchar *protocol_group;
50 EmpathyTpGroup *publish;
51 EmpathyTpGroup *subscribe;
56 GHashTable *contacts_groups;
60 TP_CONTACT_LIST_TYPE_PUBLISH,
61 TP_CONTACT_LIST_TYPE_SUBSCRIBE,
62 TP_CONTACT_LIST_TYPE_UNKNOWN
65 static void empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass);
66 static void empathy_tp_contact_list_init (EmpathyTpContactList *list);
67 static void tp_contact_list_iface_init (EmpathyContactListIface *iface);
74 static guint signals[LAST_SIGNAL];
76 G_DEFINE_TYPE_WITH_CODE (EmpathyTpContactList, empathy_tp_contact_list, G_TYPE_OBJECT,
77 G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST,
78 tp_contact_list_iface_init));
81 tp_contact_list_group_destroy_cb (EmpathyTpGroup *group,
82 EmpathyTpContactList *list)
84 EmpathyTpContactListPriv *priv = GET_PRIV (list);
86 empathy_debug (DEBUG_DOMAIN, "Group destroyed: %s",
87 empathy_tp_group_get_name (group));
89 priv->groups = g_list_remove (priv->groups, group);
90 g_object_unref (group);
94 tp_contact_list_group_member_added_cb (EmpathyTpGroup *group,
95 EmpathyContact *contact,
96 EmpathyContact *actor,
99 EmpathyTpContactList *list)
101 EmpathyTpContactListPriv *priv = GET_PRIV (list);
102 const gchar *group_name;
105 if (!g_list_find (priv->members, contact)) {
109 groups = g_hash_table_lookup (priv->contacts_groups, contact);
111 groups = g_slice_new0 (GList*);
112 g_hash_table_insert (priv->contacts_groups,
113 g_object_ref (contact),
117 group_name = empathy_tp_group_get_name (group);
118 if (!g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp)) {
119 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) added to group %s",
120 empathy_contact_get_id (contact),
121 empathy_contact_get_handle (contact),
123 *groups = g_list_prepend (*groups, g_strdup (group_name));
124 g_signal_emit_by_name (list, "groups-changed", contact,
131 tp_contact_list_group_member_removed_cb (EmpathyTpGroup *group,
132 EmpathyContact *contact,
133 EmpathyContact *actor,
135 const gchar *message,
136 EmpathyTpContactList *list)
138 EmpathyTpContactListPriv *priv = GET_PRIV (list);
139 const gchar *group_name;
142 if (!g_list_find (priv->members, contact)) {
146 groups = g_hash_table_lookup (priv->contacts_groups, contact);
151 group_name = empathy_tp_group_get_name (group);
152 if ((l = g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp))) {
153 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) removed from group %s",
154 empathy_contact_get_id (contact),
155 empathy_contact_get_handle (contact),
157 *groups = g_list_delete_link (*groups, l);
158 g_signal_emit_by_name (list, "groups-changed", contact,
164 static EmpathyTpGroup *
165 tp_contact_list_find_group (EmpathyTpContactList *list,
168 EmpathyTpContactListPriv *priv = GET_PRIV (list);
171 for (l = priv->groups; l; l = l->next) {
172 if (!tp_strdiff (group, empathy_tp_group_get_name (l->data))) {
179 static TpContactListType
180 tp_contact_list_get_type (EmpathyTpContactList *list,
181 EmpathyTpGroup *group)
185 name = empathy_tp_group_get_name (group);
186 if (!tp_strdiff (name, "subscribe")) {
187 return TP_CONTACT_LIST_TYPE_SUBSCRIBE;
188 } else if (!tp_strdiff (name, "publish")) {
189 return TP_CONTACT_LIST_TYPE_PUBLISH;
192 return TP_CONTACT_LIST_TYPE_UNKNOWN;
196 tp_contact_list_add_member (EmpathyTpContactList *list,
197 EmpathyContact *contact,
198 EmpathyContact *actor,
200 const gchar *message)
202 EmpathyTpContactListPriv *priv = GET_PRIV (list);
205 /* Add to the list and emit signal */
206 priv->members = g_list_prepend (priv->members, g_object_ref (contact));
207 g_signal_emit_by_name (list, "members-changed",
208 contact, actor, reason, message,
211 /* This contact is now member, implicitly accept pending. */
212 if (g_list_find (priv->pendings, contact)) {
213 empathy_tp_group_add_member (priv->publish, contact, "");
216 /* Update groups of the contact */
217 for (l = priv->groups; l; l = l->next) {
218 if (empathy_tp_group_is_member (l->data, contact)) {
219 tp_contact_list_group_member_added_cb (l->data, contact,
227 tp_contact_list_added_cb (EmpathyTpGroup *group,
228 EmpathyContact *contact,
229 EmpathyContact *actor,
231 const gchar *message,
232 EmpathyTpContactList *list)
234 EmpathyTpContactListPriv *priv = GET_PRIV (list);
235 TpContactListType list_type;
237 list_type = tp_contact_list_get_type (list, group);
238 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) added to list type %d",
239 empathy_contact_get_id (contact),
240 empathy_contact_get_handle (contact),
243 /* We now get the presence of that contact, add it to members */
244 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
245 !g_list_find (priv->members, contact)) {
246 tp_contact_list_add_member (list, contact, actor, reason, message);
249 /* We now send our presence to that contact, remove it from pendings */
250 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
251 g_list_find (priv->pendings, contact)) {
252 g_signal_emit_by_name (list, "pendings-changed",
253 contact, actor, reason, message,
255 priv->pendings = g_list_remove (priv->pendings, contact);
256 g_object_unref (contact);
261 tp_contact_list_removed_cb (EmpathyTpGroup *group,
262 EmpathyContact *contact,
263 EmpathyContact *actor,
265 const gchar *message,
266 EmpathyTpContactList *list)
268 EmpathyTpContactListPriv *priv = GET_PRIV (list);
269 TpContactListType list_type;
271 list_type = tp_contact_list_get_type (list, group);
272 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) removed from list type %d",
273 empathy_contact_get_id (contact),
274 empathy_contact_get_handle (contact),
277 /* This contact refuses to send us his presence, remove from members. */
278 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
279 g_list_find (priv->members, contact)) {
280 g_signal_emit_by_name (list, "members-changed",
281 contact, actor, reason, message,
283 priv->members = g_list_remove (priv->members, contact);
284 g_object_unref (contact);
287 /* We refuse to send our presence to that contact, remove from pendings */
288 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
289 g_list_find (priv->pendings, contact)) {
290 g_signal_emit_by_name (list, "pendings-changed",
291 contact, actor, reason, message,
293 priv->pendings = g_list_remove (priv->pendings, contact);
294 g_object_unref (contact);
299 tp_contact_list_pending_cb (EmpathyTpGroup *group,
300 EmpathyContact *contact,
301 EmpathyContact *actor,
303 const gchar *message,
304 EmpathyTpContactList *list)
306 EmpathyTpContactListPriv *priv = GET_PRIV (list);
307 TpContactListType list_type;
309 list_type = tp_contact_list_get_type (list, group);
310 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) pending in list type %d",
311 empathy_contact_get_id (contact),
312 empathy_contact_get_handle (contact),
315 /* We want this contact in our contact list but we don't get its
316 * presence yet. Add to members anyway. */
317 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
318 !g_list_find (priv->members, contact)) {
319 tp_contact_list_add_member (list, contact, actor, reason, message);
322 /* This contact wants our presence, auto accept if he is member,
323 * otherwise he is pending. */
324 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
325 !g_list_find (priv->pendings, contact)) {
326 if (g_list_find (priv->members, contact)) {
327 empathy_tp_group_add_member (priv->publish, contact, "");
329 priv->pendings = g_list_prepend (priv->pendings,
330 g_object_ref (contact));
331 g_signal_emit_by_name (list, "pendings-changed",
332 contact, actor, reason, message,
339 tp_contact_list_newchannel_cb (DBusGProxy *proxy,
340 const gchar *object_path,
341 const gchar *channel_type,
342 TpHandleType handle_type,
343 guint channel_handle,
344 gboolean suppress_handler,
345 EmpathyTpContactList *list)
347 EmpathyTpContactListPriv *priv = GET_PRIV (list);
348 EmpathyTpGroup *group;
350 const gchar *bus_name;
352 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) != 0 ||
357 bus_name = dbus_g_proxy_get_bus_name (DBUS_G_PROXY (priv->tp_conn));
358 new_chan = tp_chan_new (tp_get_bus (),
364 g_return_if_fail (TELEPATHY_IS_CHAN (new_chan));
366 group = empathy_tp_group_new (priv->account, new_chan);
367 g_object_unref (new_chan);
369 if (handle_type == TP_HANDLE_TYPE_LIST) {
370 TpContactListType list_type;
373 list_type = tp_contact_list_get_type (list, group);
374 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && !priv->publish) {
375 priv->publish = group;
377 /* Publish is the list of contacts to who we send our
378 * presence. Makes no sense to be in remote-pending */
379 g_signal_connect (group, "local-pending",
380 G_CALLBACK (tp_contact_list_pending_cb),
383 contacts = empathy_tp_group_get_local_pendings (group);
384 for (l = contacts; l; l = l->next) {
385 EmpathyPendingInfo *info = l->data;
387 tp_contact_list_pending_cb (group,
393 empathy_pending_info_free (info);
395 g_list_free (contacts);
397 else if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && !priv->subscribe) {
398 priv->subscribe = group;
400 /* Subscribe is the list of contacts from who we
401 * receive presence. Makes no sense to be in
403 g_signal_connect (group, "remote-pending",
404 G_CALLBACK (tp_contact_list_pending_cb),
407 contacts = empathy_tp_group_get_remote_pendings (group);
408 for (l = contacts; l; l = l->next) {
409 tp_contact_list_pending_cb (group,
413 g_object_unref (l->data);
415 g_list_free (contacts);
417 empathy_debug (DEBUG_DOMAIN,
418 "Type of contact list channel unknown "
419 "or aleady have that list: %s",
420 empathy_tp_group_get_name (group));
421 g_object_unref (group);
424 empathy_debug (DEBUG_DOMAIN,
425 "New contact list channel of type: %d",
428 g_signal_connect (group, "member-added",
429 G_CALLBACK (tp_contact_list_added_cb),
431 g_signal_connect (group, "member-removed",
432 G_CALLBACK (tp_contact_list_removed_cb),
435 contacts = empathy_tp_group_get_members (group);
436 for (l = contacts; l; l = l->next) {
437 tp_contact_list_added_cb (group,
441 g_object_unref (l->data);
443 g_list_free (contacts);
445 else if (handle_type == TP_HANDLE_TYPE_GROUP) {
446 const gchar *group_name;
449 /* Check if already exists */
450 group_name = empathy_tp_group_get_name (group);
451 if (tp_contact_list_find_group (list, group_name)) {
452 g_object_unref (group);
456 empathy_debug (DEBUG_DOMAIN, "New server-side group channel: %s",
459 priv->groups = g_list_prepend (priv->groups, group);
461 g_signal_connect (group, "member-added",
462 G_CALLBACK (tp_contact_list_group_member_added_cb),
464 g_signal_connect (group, "member-removed",
465 G_CALLBACK (tp_contact_list_group_member_removed_cb),
467 g_signal_connect (group, "destroy",
468 G_CALLBACK (tp_contact_list_group_destroy_cb),
471 contacts = empathy_tp_group_get_members (group);
472 for (l = contacts; l; l = l->next) {
473 tp_contact_list_group_member_added_cb (group, l->data,
476 g_object_unref (l->data);
478 g_list_free (contacts);
480 empathy_debug (DEBUG_DOMAIN,
481 "Unknown handle type (%d) for contact list channel",
483 g_object_unref (group);
488 tp_contact_list_destroy_cb (TpConn *tp_conn,
489 EmpathyTpContactList *list)
491 EmpathyTpContactListPriv *priv = GET_PRIV (list);
494 empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed");
496 /* DBus proxie should NOT be used anymore */
497 g_object_unref (priv->tp_conn);
498 priv->tp_conn = NULL;
500 /* Remove all contacts */
501 for (l = priv->members; l; l = l->next) {
502 g_signal_emit_by_name (list, "members-changed", l->data,
505 g_object_unref (l->data);
507 for (l = priv->pendings; l; l = l->next) {
508 g_signal_emit_by_name (list, "pendings-changed", l->data,
511 g_object_unref (l->data);
513 g_list_free (priv->members);
514 g_list_free (priv->pendings);
515 priv->members = NULL;
516 priv->pendings = NULL;
518 /* Tell the world to not use us anymore */
519 g_signal_emit (list, signals[DESTROY], 0);
523 tp_contact_list_disconnect (EmpathyTpContactList *list)
525 EmpathyTpContactListPriv *priv = GET_PRIV (list);
528 g_signal_handlers_disconnect_by_func (priv->tp_conn,
529 tp_contact_list_destroy_cb,
531 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->tp_conn), "NewChannel",
532 G_CALLBACK (tp_contact_list_newchannel_cb),
538 tp_contact_list_status_changed_cb (MissionControl *mc,
539 TpConnectionStatus status,
541 TpConnectionStatusReason reason,
542 const gchar *unique_name,
543 EmpathyTpContactList *list)
545 EmpathyTpContactListPriv *priv = GET_PRIV (list);
548 account = mc_account_lookup (unique_name);
549 if (status != TP_CONNECTION_STATUS_CONNECTED &&
550 empathy_account_equal (account, priv->account)) {
551 /* We are disconnected */
552 tp_contact_list_disconnect (list);
553 tp_contact_list_destroy_cb (priv->tp_conn, list);
556 g_object_unref (account);
560 tp_contact_list_group_list_free (GList **groups)
562 g_list_foreach (*groups, (GFunc) g_free, NULL);
563 g_list_free (*groups);
564 g_slice_free (GList*, groups);
568 tp_contact_list_finalize (GObject *object)
570 EmpathyTpContactListPriv *priv;
571 EmpathyTpContactList *list;
573 list = EMPATHY_TP_CONTACT_LIST (object);
574 priv = GET_PRIV (list);
576 empathy_debug (DEBUG_DOMAIN, "finalize: %p", object);
578 tp_contact_list_disconnect (list);
581 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
582 "AccountStatusChanged",
583 G_CALLBACK (tp_contact_list_status_changed_cb),
585 g_object_unref (priv->mc);
588 if (priv->subscribe) {
589 g_object_unref (priv->subscribe);
592 g_object_unref (priv->publish);
595 g_object_unref (priv->account);
598 g_object_unref (priv->tp_conn);
601 g_hash_table_destroy (priv->contacts_groups);
602 g_list_foreach (priv->groups, (GFunc) g_object_unref, NULL);
603 g_list_free (priv->groups);
604 g_list_foreach (priv->members, (GFunc) g_object_unref, NULL);
605 g_list_free (priv->members);
606 g_list_foreach (priv->pendings, (GFunc) g_object_unref, NULL);
607 g_list_free (priv->pendings);
609 G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object);
613 empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass)
615 GObjectClass *object_class = G_OBJECT_CLASS (klass);
617 object_class->finalize = tp_contact_list_finalize;
620 g_signal_new ("destroy",
621 G_TYPE_FROM_CLASS (klass),
625 g_cclosure_marshal_VOID__VOID,
629 g_type_class_add_private (object_class, sizeof (EmpathyTpContactListPriv));
633 empathy_tp_contact_list_init (EmpathyTpContactList *list)
638 tp_contact_list_setup (EmpathyTpContactList *list)
640 EmpathyTpContactListPriv *priv = GET_PRIV (list);
643 GError *error = NULL;
645 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
647 /* Get existing channels */
648 if (!tp_conn_list_channels (DBUS_G_PROXY (priv->tp_conn),
651 empathy_debug (DEBUG_DOMAIN,
652 "Failed to get list of open channels: %s",
653 error ? error->message : "No error given");
654 g_clear_error (&error);
658 for (i = 0; i < channels->len; i++) {
659 GValueArray *chan_struct;
660 const gchar *object_path;
661 const gchar *chan_iface;
662 TpHandleType handle_type;
665 chan_struct = g_ptr_array_index (channels, i);
666 object_path = g_value_get_boxed (g_value_array_get_nth (chan_struct, 0));
667 chan_iface = g_value_get_string (g_value_array_get_nth (chan_struct, 1));
668 handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2));
669 handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3));
671 tp_contact_list_newchannel_cb (DBUS_G_PROXY (priv->tp_conn),
672 object_path, chan_iface,
677 g_value_array_free (chan_struct);
679 g_ptr_array_free (channels, TRUE);
682 EmpathyTpContactList *
683 empathy_tp_contact_list_new (McAccount *account)
685 EmpathyTpContactListPriv *priv;
686 EmpathyTpContactList *list;
688 TpConn *tp_conn = NULL;
690 const gchar *protocol_name;
692 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
694 mc = empathy_mission_control_new ();
696 /* status==0 means CONNECTED */
697 if (mission_control_get_connection_status (mc, account, NULL) == 0) {
698 tp_conn = mission_control_get_connection (mc, account, NULL);
701 /* The account is not connected, nothing to do. */
706 list = g_object_new (EMPATHY_TYPE_TP_CONTACT_LIST, NULL);
707 priv = GET_PRIV (list);
709 priv->tp_conn = tp_conn;
710 priv->account = g_object_ref (account);
712 priv->contacts_groups = g_hash_table_new_full (empathy_contact_hash,
713 empathy_contact_equal,
714 (GDestroyNotify) g_object_unref,
715 (GDestroyNotify) tp_contact_list_group_list_free);
717 /* Check for protocols that does not support contact groups. We can
718 * put all contacts into a special group in that case.
719 * FIXME: Default group should be an information in the profile */
720 profile = mc_account_get_profile (account);
721 protocol_name = mc_profile_get_protocol_name (profile);
722 if (strcmp (protocol_name, "local-xmpp") == 0) {
723 priv->protocol_group = _("People nearby");
725 g_object_unref (profile);
727 /* Connect signals */
728 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
729 "AccountStatusChanged",
730 G_CALLBACK (tp_contact_list_status_changed_cb),
732 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->tp_conn), "NewChannel",
733 G_CALLBACK (tp_contact_list_newchannel_cb),
735 g_signal_connect (priv->tp_conn, "destroy",
736 G_CALLBACK (tp_contact_list_destroy_cb),
739 tp_contact_list_setup (list);
745 empathy_tp_contact_list_get_account (EmpathyTpContactList *list)
747 EmpathyTpContactListPriv *priv;
749 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
751 priv = GET_PRIV (list);
753 return priv->account;
757 tp_contact_list_add (EmpathyContactList *list,
758 EmpathyContact *contact,
759 const gchar *message)
761 EmpathyTpContactListPriv *priv = GET_PRIV (list);
763 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
765 empathy_tp_group_add_member (priv->subscribe, contact, message);
766 if (g_list_find (priv->pendings, contact)) {
767 empathy_tp_group_add_member (priv->publish, contact, message);
772 tp_contact_list_remove (EmpathyContactList *list,
773 EmpathyContact *contact,
774 const gchar *message)
776 EmpathyTpContactListPriv *priv = GET_PRIV (list);
778 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
780 empathy_tp_group_remove_member (priv->subscribe, contact, message);
781 empathy_tp_group_remove_member (priv->publish, contact, message);
785 tp_contact_list_get_members (EmpathyContactList *list)
787 EmpathyTpContactListPriv *priv = GET_PRIV (list);
789 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
791 g_list_foreach (priv->members, (GFunc) g_object_ref, NULL);
792 return g_list_copy (priv->members);
796 tp_contact_list_get_pendings (EmpathyContactList *list)
798 EmpathyTpContactListPriv *priv = GET_PRIV (list);
800 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
802 g_list_foreach (priv->pendings, (GFunc) g_object_ref, NULL);
803 return g_list_copy (priv->pendings);
807 tp_contact_list_get_all_groups (EmpathyContactList *list)
809 EmpathyTpContactListPriv *priv = GET_PRIV (list);
810 GList *groups = NULL, *l;
812 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
814 if (priv->protocol_group) {
815 groups = g_list_prepend (groups, g_strdup (priv->protocol_group));
818 for (l = priv->groups; l; l = l->next) {
821 name = empathy_tp_group_get_name (l->data);
822 groups = g_list_prepend (groups, g_strdup (name));
829 tp_contact_list_get_groups (EmpathyContactList *list,
830 EmpathyContact *contact)
832 EmpathyTpContactListPriv *priv = GET_PRIV (list);
834 GList *ret = NULL, *l;
836 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
838 if (priv->protocol_group) {
839 ret = g_list_prepend (ret, g_strdup (priv->protocol_group));
842 groups = g_hash_table_lookup (priv->contacts_groups, contact);
847 for (l = *groups; l; l = l->next) {
848 ret = g_list_prepend (ret, g_strdup (l->data));
855 static EmpathyTpGroup *
856 tp_contact_list_get_group (EmpathyTpContactList *list,
859 EmpathyTpContactListPriv *priv = GET_PRIV (list);
860 EmpathyTpGroup *tp_group;
864 const char *names[2] = {group, NULL};
865 GError *error = NULL;
867 tp_group = tp_contact_list_find_group (list, group);
872 empathy_debug (DEBUG_DOMAIN, "creating new group: %s", group);
874 if (!tp_conn_request_handles (DBUS_G_PROXY (priv->tp_conn),
875 TP_HANDLE_TYPE_GROUP,
879 empathy_debug (DEBUG_DOMAIN,
880 "Failed to RequestHandles: %s",
881 error ? error->message : "No error given");
882 g_clear_error (&error);
885 handle = g_array_index (handles, guint, 0);
886 g_array_free (handles, TRUE);
888 if (!tp_conn_request_channel (DBUS_G_PROXY (priv->tp_conn),
889 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
890 TP_HANDLE_TYPE_GROUP,
895 empathy_debug (DEBUG_DOMAIN,
896 "Failed to RequestChannel: %s",
897 error ? error->message : "No error given");
898 g_clear_error (&error);
902 tp_contact_list_newchannel_cb (DBUS_G_PROXY (priv->tp_conn),
904 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
905 TP_HANDLE_TYPE_GROUP,
908 g_free (object_path);
910 return tp_contact_list_find_group (list, group);
914 tp_contact_list_add_to_group (EmpathyContactList *list,
915 EmpathyContact *contact,
918 EmpathyTpGroup *tp_group;
920 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
922 tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
925 empathy_tp_group_add_member (tp_group, contact, "");
929 tp_contact_list_remove_from_group (EmpathyContactList *list,
930 EmpathyContact *contact,
933 EmpathyTpGroup *tp_group;
935 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
937 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
941 empathy_tp_group_remove_member (tp_group, contact, "");
946 tp_contact_list_rename_group (EmpathyContactList *list,
947 const gchar *old_group,
948 const gchar *new_group)
950 EmpathyTpGroup *tp_group;
953 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
955 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
961 empathy_debug (DEBUG_DOMAIN, "rename group %s to %s", old_group, new_group);
963 /* Remove all members from the old group */
964 members = empathy_tp_group_get_members (tp_group);
965 empathy_tp_group_remove_members (tp_group, members, "");
966 empathy_tp_group_close (tp_group);
968 /* Add all members to the new group */
969 tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
971 empathy_tp_group_add_members (tp_group, members, "");
973 g_list_foreach (members, (GFunc) g_object_unref, NULL);
974 g_list_free (members);
978 tp_contact_list_remove_group (EmpathyContactList *list,
981 EmpathyTpGroup *tp_group;
984 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
986 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
993 empathy_debug (DEBUG_DOMAIN, "remove group %s", group);
995 /* Remove all members of the group */
996 members = empathy_tp_group_get_members (tp_group);
997 empathy_tp_group_remove_members (tp_group, members, "");
998 empathy_tp_group_close (tp_group);
1000 g_list_foreach (members, (GFunc) g_object_unref, NULL);
1001 g_list_free (members);
1005 tp_contact_list_iface_init (EmpathyContactListIface *iface)
1007 iface->add = tp_contact_list_add;
1008 iface->remove = tp_contact_list_remove;
1009 iface->get_members = tp_contact_list_get_members;
1010 iface->get_pendings = tp_contact_list_get_pendings;
1011 iface->get_all_groups = tp_contact_list_get_all_groups;
1012 iface->get_groups = tp_contact_list_get_groups;
1013 iface->add_to_group = tp_contact_list_add_to_group;
1014 iface->remove_from_group = tp_contact_list_remove_from_group;
1015 iface->rename_group = tp_contact_list_rename_group;
1016 iface->remove_group = tp_contact_list_remove_group;