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 program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program 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 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
21 * Authors: Xavier Claessens <xclaesse@gmail.com>
27 #include <glib/gi18n.h>
29 #include <libtelepathy/tp-helpers.h>
30 #include <libtelepathy/tp-conn.h>
31 #include <libtelepathy/tp-chan.h>
32 #include <libtelepathy/tp-chan-type-contact-list-gen.h>
34 #include "empathy-tp-contact-list.h"
35 #include "empathy-contact-list.h"
36 #include "empathy-tp-group.h"
37 #include "empathy-debug.h"
38 #include "empathy-utils.h"
40 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
41 EMPATHY_TYPE_TP_CONTACT_LIST, EmpathyTpContactListPriv))
43 #define DEBUG_DOMAIN "TpContactList"
45 struct _EmpathyTpContactListPriv {
49 const gchar *protocol_group;
51 EmpathyTpGroup *publish;
52 EmpathyTpGroup *subscribe;
57 GHashTable *contacts_groups;
61 TP_CONTACT_LIST_TYPE_PUBLISH,
62 TP_CONTACT_LIST_TYPE_SUBSCRIBE,
63 TP_CONTACT_LIST_TYPE_UNKNOWN
66 static void empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass);
67 static void empathy_tp_contact_list_init (EmpathyTpContactList *list);
68 static void tp_contact_list_iface_init (EmpathyContactListIface *iface);
75 static guint signals[LAST_SIGNAL];
77 G_DEFINE_TYPE_WITH_CODE (EmpathyTpContactList, empathy_tp_contact_list, G_TYPE_OBJECT,
78 G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST,
79 tp_contact_list_iface_init));
82 tp_contact_list_group_destroy_cb (EmpathyTpGroup *group,
83 EmpathyTpContactList *list)
85 EmpathyTpContactListPriv *priv = GET_PRIV (list);
87 empathy_debug (DEBUG_DOMAIN, "Group destroyed: %s",
88 empathy_tp_group_get_name (group));
90 priv->groups = g_list_remove (priv->groups, group);
91 g_object_unref (group);
95 tp_contact_list_group_member_added_cb (EmpathyTpGroup *group,
96 EmpathyContact *contact,
97 EmpathyContact *actor,
100 EmpathyTpContactList *list)
102 EmpathyTpContactListPriv *priv = GET_PRIV (list);
103 const gchar *group_name;
106 if (!g_list_find (priv->members, contact)) {
110 groups = g_hash_table_lookup (priv->contacts_groups, contact);
112 groups = g_slice_new0 (GList*);
113 g_hash_table_insert (priv->contacts_groups,
114 g_object_ref (contact),
118 group_name = empathy_tp_group_get_name (group);
119 if (!g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp)) {
120 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) added to group %s",
121 empathy_contact_get_id (contact),
122 empathy_contact_get_handle (contact),
124 *groups = g_list_prepend (*groups, g_strdup (group_name));
125 g_signal_emit_by_name (list, "groups-changed", contact,
132 tp_contact_list_group_member_removed_cb (EmpathyTpGroup *group,
133 EmpathyContact *contact,
134 EmpathyContact *actor,
136 const gchar *message,
137 EmpathyTpContactList *list)
139 EmpathyTpContactListPriv *priv = GET_PRIV (list);
140 const gchar *group_name;
143 if (!g_list_find (priv->members, contact)) {
147 groups = g_hash_table_lookup (priv->contacts_groups, contact);
152 group_name = empathy_tp_group_get_name (group);
153 if ((l = g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp))) {
154 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) removed from group %s",
155 empathy_contact_get_id (contact),
156 empathy_contact_get_handle (contact),
158 *groups = g_list_delete_link (*groups, l);
159 g_signal_emit_by_name (list, "groups-changed", contact,
165 static EmpathyTpGroup *
166 tp_contact_list_find_group (EmpathyTpContactList *list,
169 EmpathyTpContactListPriv *priv = GET_PRIV (list);
172 for (l = priv->groups; l; l = l->next) {
173 if (strcmp (group, empathy_tp_group_get_name (l->data)) == 0) {
180 static TpContactListType
181 tp_contact_list_get_type (EmpathyTpContactList *list,
182 EmpathyTpGroup *group)
184 EmpathyTpContactListPriv *priv;
185 TpContactListType list_type;
188 priv = GET_PRIV (list);
190 name = empathy_tp_group_get_name (group);
191 if (strcmp (name, "subscribe") == 0) {
192 list_type = TP_CONTACT_LIST_TYPE_SUBSCRIBE;
193 } else if (strcmp (name, "publish") == 0) {
194 list_type = TP_CONTACT_LIST_TYPE_PUBLISH;
196 list_type = TP_CONTACT_LIST_TYPE_UNKNOWN;
203 tp_contact_list_add_member (EmpathyTpContactList *list,
204 EmpathyContact *contact,
205 EmpathyContact *actor,
207 const gchar *message)
209 EmpathyTpContactListPriv *priv = GET_PRIV (list);
212 /* Add to the list and emit signal */
213 priv->members = g_list_prepend (priv->members, g_object_ref (contact));
214 g_signal_emit_by_name (list, "members-changed",
215 contact, actor, reason, message,
218 /* This contact is now member, implicitly accept pending. */
219 if (g_list_find (priv->pendings, contact)) {
220 empathy_tp_group_add_member (priv->publish, contact, "");
223 /* Update groups of the contact */
224 for (l = priv->groups; l; l = l->next) {
225 if (empathy_tp_group_is_member (l->data, contact)) {
226 tp_contact_list_group_member_added_cb (l->data, contact,
234 tp_contact_list_added_cb (EmpathyTpGroup *group,
235 EmpathyContact *contact,
236 EmpathyContact *actor,
238 const gchar *message,
239 EmpathyTpContactList *list)
241 EmpathyTpContactListPriv *priv = GET_PRIV (list);
242 TpContactListType list_type;
244 list_type = tp_contact_list_get_type (list, group);
245 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) added to list type %d",
246 empathy_contact_get_id (contact),
247 empathy_contact_get_handle (contact),
250 /* We now get the presence of that contact, add it to members */
251 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
252 !g_list_find (priv->members, contact)) {
253 tp_contact_list_add_member (list, contact, actor, reason, message);
256 /* We now send our presence to that contact, remove it from pendings */
257 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
258 g_list_find (priv->pendings, contact)) {
259 g_signal_emit_by_name (list, "pendings-changed",
260 contact, actor, reason, message,
262 priv->pendings = g_list_remove (priv->pendings, contact);
263 g_object_unref (contact);
268 tp_contact_list_removed_cb (EmpathyTpGroup *group,
269 EmpathyContact *contact,
270 EmpathyContact *actor,
272 const gchar *message,
273 EmpathyTpContactList *list)
275 EmpathyTpContactListPriv *priv = GET_PRIV (list);
276 TpContactListType list_type;
278 list_type = tp_contact_list_get_type (list, group);
279 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) removed from list type %d",
280 empathy_contact_get_id (contact),
281 empathy_contact_get_handle (contact),
284 /* This contact refuses to send us his presence, remove from members. */
285 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
286 g_list_find (priv->members, contact)) {
287 g_signal_emit_by_name (list, "members-changed",
288 contact, actor, reason, message,
290 priv->members = g_list_remove (priv->members, contact);
291 g_object_unref (contact);
294 /* We refuse to send our presence to that contact, remove from pendings */
295 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
296 g_list_find (priv->pendings, contact)) {
297 g_signal_emit_by_name (list, "pendings-changed",
298 contact, actor, reason, message,
300 priv->pendings = g_list_remove (priv->pendings, contact);
301 g_object_unref (contact);
306 tp_contact_list_pending_cb (EmpathyTpGroup *group,
307 EmpathyContact *contact,
308 EmpathyContact *actor,
310 const gchar *message,
311 EmpathyTpContactList *list)
313 EmpathyTpContactListPriv *priv = GET_PRIV (list);
314 TpContactListType list_type;
316 list_type = tp_contact_list_get_type (list, group);
317 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) pending in list type %d",
318 empathy_contact_get_id (contact),
319 empathy_contact_get_handle (contact),
322 /* We want this contact in our contact list but we don't get its
323 * presence yet. Add to members anyway. */
324 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
325 !g_list_find (priv->members, contact)) {
326 tp_contact_list_add_member (list, contact, actor, reason, message);
329 /* This contact wants our presence, auto accept if he is member,
330 * otherwise he is pending. */
331 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
332 !g_list_find (priv->pendings, contact)) {
333 if (g_list_find (priv->members, contact)) {
334 empathy_tp_group_add_member (priv->publish, contact, "");
336 priv->pendings = g_list_prepend (priv->pendings,
337 g_object_ref (contact));
338 g_signal_emit_by_name (list, "pendings-changed",
339 contact, actor, reason, message,
346 tp_contact_list_newchannel_cb (DBusGProxy *proxy,
347 const gchar *object_path,
348 const gchar *channel_type,
349 TelepathyHandleType handle_type,
350 guint channel_handle,
351 gboolean suppress_handle,
352 EmpathyTpContactList *list)
354 EmpathyTpContactListPriv *priv = GET_PRIV (list);
355 EmpathyTpGroup *group;
357 const gchar *bus_name;
359 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) != 0 ||
364 bus_name = dbus_g_proxy_get_bus_name (DBUS_G_PROXY (priv->tp_conn));
365 new_chan = tp_chan_new (tp_get_bus (),
371 g_return_if_fail (TELEPATHY_IS_CHAN (new_chan));
373 group = empathy_tp_group_new (priv->account, new_chan);
374 g_object_unref (new_chan);
376 if (handle_type == TP_HANDLE_TYPE_LIST) {
377 TpContactListType list_type;
380 list_type = tp_contact_list_get_type (list, group);
381 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && !priv->publish) {
382 priv->publish = group;
384 /* Publish is the list of contacts to who we send our
385 * presence. Makes no sense to be in remote-pending */
386 g_signal_connect (group, "local-pending",
387 G_CALLBACK (tp_contact_list_pending_cb),
390 contacts = empathy_tp_group_get_local_pendings (group);
391 for (l = contacts; l; l = l->next) {
392 EmpathyPendingInfo *info = l->data;
394 tp_contact_list_pending_cb (group,
400 empathy_pending_info_free (info);
402 g_list_free (contacts);
404 else if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && !priv->subscribe) {
405 priv->subscribe = group;
407 /* Subscribe is the list of contacts from who we
408 * receive presence. Makes no sense to be in
410 g_signal_connect (group, "remote-pending",
411 G_CALLBACK (tp_contact_list_pending_cb),
414 contacts = empathy_tp_group_get_remote_pendings (group);
415 for (l = contacts; l; l = l->next) {
416 tp_contact_list_pending_cb (group,
420 g_object_unref (l->data);
422 g_list_free (contacts);
424 empathy_debug (DEBUG_DOMAIN,
425 "Type of contact list channel unknown "
426 "or aleady have that list: %s",
427 empathy_tp_group_get_name (group));
428 g_object_unref (group);
431 empathy_debug (DEBUG_DOMAIN,
432 "New contact list channel of type: %d",
435 g_signal_connect (group, "member-added",
436 G_CALLBACK (tp_contact_list_added_cb),
438 g_signal_connect (group, "member-removed",
439 G_CALLBACK (tp_contact_list_removed_cb),
442 contacts = empathy_tp_group_get_members (group);
443 for (l = contacts; l; l = l->next) {
444 tp_contact_list_added_cb (group,
448 g_object_unref (l->data);
450 g_list_free (contacts);
452 else if (handle_type == TP_HANDLE_TYPE_GROUP) {
453 const gchar *group_name;
456 /* Check if already exists */
457 group_name = empathy_tp_group_get_name (group);
458 if (tp_contact_list_find_group (list, group_name)) {
459 g_object_unref (group);
463 empathy_debug (DEBUG_DOMAIN, "New server-side group channel: %s",
466 priv->groups = g_list_prepend (priv->groups, group);
468 g_signal_connect (group, "member-added",
469 G_CALLBACK (tp_contact_list_group_member_added_cb),
471 g_signal_connect (group, "member-removed",
472 G_CALLBACK (tp_contact_list_group_member_removed_cb),
474 g_signal_connect (group, "destroy",
475 G_CALLBACK (tp_contact_list_group_destroy_cb),
478 contacts = empathy_tp_group_get_members (group);
479 for (l = contacts; l; l = l->next) {
480 tp_contact_list_group_member_added_cb (group, l->data,
483 g_object_unref (l->data);
485 g_list_free (contacts);
487 empathy_debug (DEBUG_DOMAIN,
488 "Unknown handle type (%d) for contact list channel",
490 g_object_unref (group);
495 tp_contact_list_destroy_cb (TpConn *tp_conn,
496 EmpathyTpContactList *list)
498 EmpathyTpContactListPriv *priv = GET_PRIV (list);
501 empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed");
503 /* DBus proxie should NOT be used anymore */
504 g_object_unref (priv->tp_conn);
505 priv->tp_conn = NULL;
507 /* Remove all contacts */
508 for (l = priv->members; l; l = l->next) {
509 g_signal_emit_by_name (list, "members-changed", l->data,
512 g_object_unref (l->data);
514 for (l = priv->pendings; l; l = l->next) {
515 g_signal_emit_by_name (list, "pendings-changed", l->data,
518 g_object_unref (l->data);
520 g_list_free (priv->members);
521 g_list_free (priv->pendings);
522 priv->members = NULL;
523 priv->pendings = NULL;
525 /* Tell the world to not use us anymore */
526 g_signal_emit (list, signals[DESTROY], 0);
530 tp_contact_list_disconnect (EmpathyTpContactList *list)
532 EmpathyTpContactListPriv *priv = GET_PRIV (list);
535 g_signal_handlers_disconnect_by_func (priv->tp_conn,
536 tp_contact_list_destroy_cb,
538 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->tp_conn), "NewChannel",
539 G_CALLBACK (tp_contact_list_newchannel_cb),
545 tp_contact_list_status_changed_cb (MissionControl *mc,
546 TelepathyConnectionStatus status,
548 TelepathyConnectionStatusReason reason,
549 const gchar *unique_name,
550 EmpathyTpContactList *list)
552 EmpathyTpContactListPriv *priv = GET_PRIV (list);
555 account = mc_account_lookup (unique_name);
556 if (status != TP_CONN_STATUS_CONNECTED &&
557 empathy_account_equal (account, priv->account)) {
558 /* We are disconnected */
559 tp_contact_list_disconnect (list);
560 tp_contact_list_destroy_cb (priv->tp_conn, list);
563 g_object_unref (account);
567 tp_contact_list_group_list_free (GList **groups)
569 g_list_foreach (*groups, (GFunc) g_free, NULL);
570 g_list_free (*groups);
571 g_slice_free (GList*, groups);
575 tp_contact_list_finalize (GObject *object)
577 EmpathyTpContactListPriv *priv;
578 EmpathyTpContactList *list;
580 list = EMPATHY_TP_CONTACT_LIST (object);
581 priv = GET_PRIV (list);
583 empathy_debug (DEBUG_DOMAIN, "finalize: %p", object);
585 tp_contact_list_disconnect (list);
588 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
589 "AccountStatusChanged",
590 G_CALLBACK (tp_contact_list_status_changed_cb),
592 g_object_unref (priv->mc);
595 if (priv->subscribe) {
596 g_object_unref (priv->subscribe);
599 g_object_unref (priv->publish);
602 g_object_unref (priv->account);
605 g_object_unref (priv->tp_conn);
608 g_hash_table_destroy (priv->contacts_groups);
609 g_list_foreach (priv->groups, (GFunc) g_object_unref, NULL);
610 g_list_free (priv->groups);
611 g_list_foreach (priv->members, (GFunc) g_object_unref, NULL);
612 g_list_free (priv->members);
613 g_list_foreach (priv->pendings, (GFunc) g_object_unref, NULL);
614 g_list_free (priv->pendings);
616 G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object);
620 empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass)
622 GObjectClass *object_class = G_OBJECT_CLASS (klass);
624 object_class->finalize = tp_contact_list_finalize;
627 g_signal_new ("destroy",
628 G_TYPE_FROM_CLASS (klass),
632 g_cclosure_marshal_VOID__VOID,
636 g_type_class_add_private (object_class, sizeof (EmpathyTpContactListPriv));
640 empathy_tp_contact_list_init (EmpathyTpContactList *list)
645 tp_contact_list_setup (EmpathyTpContactList *list)
647 EmpathyTpContactListPriv *priv = GET_PRIV (list);
650 GError *error = NULL;
652 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
654 /* Get existing channels */
655 if (!tp_conn_list_channels (DBUS_G_PROXY (priv->tp_conn),
658 empathy_debug (DEBUG_DOMAIN,
659 "Failed to get list of open channels: %s",
660 error ? error->message : "No error given");
661 g_clear_error (&error);
665 for (i = 0; i < channels->len; i++) {
666 GValueArray *chan_struct;
667 const gchar *object_path;
668 const gchar *chan_iface;
669 TelepathyHandleType handle_type;
672 chan_struct = g_ptr_array_index (channels, i);
673 object_path = g_value_get_boxed (g_value_array_get_nth (chan_struct, 0));
674 chan_iface = g_value_get_string (g_value_array_get_nth (chan_struct, 1));
675 handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2));
676 handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3));
678 tp_contact_list_newchannel_cb (DBUS_G_PROXY (priv->tp_conn),
679 object_path, chan_iface,
684 g_value_array_free (chan_struct);
686 g_ptr_array_free (channels, TRUE);
689 EmpathyTpContactList *
690 empathy_tp_contact_list_new (McAccount *account)
692 EmpathyTpContactListPriv *priv;
693 EmpathyTpContactList *list;
695 TpConn *tp_conn = NULL;
697 const gchar *protocol_name;
699 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
701 mc = empathy_mission_control_new ();
703 /* status==0 means CONNECTED */
704 if (mission_control_get_connection_status (mc, account, NULL) == 0) {
705 tp_conn = mission_control_get_connection (mc, account, NULL);
708 /* The account is not connected, nothing to do. */
713 list = g_object_new (EMPATHY_TYPE_TP_CONTACT_LIST, NULL);
714 priv = GET_PRIV (list);
716 priv->tp_conn = tp_conn;
717 priv->account = g_object_ref (account);
719 priv->contacts_groups = g_hash_table_new_full (empathy_contact_hash,
720 empathy_contact_equal,
721 (GDestroyNotify) g_object_unref,
722 (GDestroyNotify) tp_contact_list_group_list_free);
724 /* Check for protocols that does not support contact groups. We can
725 * put all contacts into a special group in that case.
726 * FIXME: Default group should be an information in the profile */
727 profile = mc_account_get_profile (account);
728 protocol_name = mc_profile_get_protocol_name (profile);
729 if (strcmp (protocol_name, "local-xmpp") == 0) {
730 priv->protocol_group = _("People nearby");
732 g_object_unref (profile);
734 /* Connect signals */
735 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
736 "AccountStatusChanged",
737 G_CALLBACK (tp_contact_list_status_changed_cb),
739 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->tp_conn), "NewChannel",
740 G_CALLBACK (tp_contact_list_newchannel_cb),
742 g_signal_connect (priv->tp_conn, "destroy",
743 G_CALLBACK (tp_contact_list_destroy_cb),
746 tp_contact_list_setup (list);
752 empathy_tp_contact_list_get_account (EmpathyTpContactList *list)
754 EmpathyTpContactListPriv *priv;
756 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
758 priv = GET_PRIV (list);
760 return priv->account;
764 tp_contact_list_add (EmpathyContactList *list,
765 EmpathyContact *contact,
766 const gchar *message)
768 EmpathyTpContactListPriv *priv = GET_PRIV (list);
770 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
772 empathy_tp_group_add_member (priv->subscribe, contact, message);
773 if (g_list_find (priv->pendings, contact)) {
774 empathy_tp_group_add_member (priv->publish, contact, message);
779 tp_contact_list_remove (EmpathyContactList *list,
780 EmpathyContact *contact,
781 const gchar *message)
783 EmpathyTpContactListPriv *priv = GET_PRIV (list);
785 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
787 empathy_tp_group_remove_member (priv->subscribe, contact, message);
788 empathy_tp_group_remove_member (priv->publish, contact, message);
792 tp_contact_list_get_members (EmpathyContactList *list)
794 EmpathyTpContactListPriv *priv = GET_PRIV (list);
796 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
798 g_list_foreach (priv->members, (GFunc) g_object_ref, NULL);
799 return g_list_copy (priv->members);
803 tp_contact_list_get_pendings (EmpathyContactList *list)
805 EmpathyTpContactListPriv *priv = GET_PRIV (list);
807 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
809 g_list_foreach (priv->pendings, (GFunc) g_object_ref, NULL);
810 return g_list_copy (priv->pendings);
814 tp_contact_list_get_all_groups (EmpathyContactList *list)
816 EmpathyTpContactListPriv *priv = GET_PRIV (list);
817 GList *groups = NULL, *l;
819 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
821 for (l = priv->groups; l; l = l->next) {
824 name = empathy_tp_group_get_name (l->data);
825 groups = g_list_prepend (groups, g_strdup (name));
832 tp_contact_list_get_groups (EmpathyContactList *list,
833 EmpathyContact *contact)
835 EmpathyTpContactListPriv *priv = GET_PRIV (list);
837 GList *ret = NULL, *l;
839 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
841 groups = g_hash_table_lookup (priv->contacts_groups, contact);
846 for (l = *groups; l; l = l->next) {
847 ret = g_list_prepend (ret, g_strdup (l->data));
853 static EmpathyTpGroup *
854 tp_contact_list_get_group (EmpathyTpContactList *list,
857 EmpathyTpContactListPriv *priv = GET_PRIV (list);
858 EmpathyTpGroup *tp_group;
862 const char *names[2] = {group, NULL};
863 GError *error = NULL;
865 tp_group = tp_contact_list_find_group (list, group);
870 empathy_debug (DEBUG_DOMAIN, "creating new group: %s", group);
872 if (!tp_conn_request_handles (DBUS_G_PROXY (priv->tp_conn),
873 TP_HANDLE_TYPE_GROUP,
877 empathy_debug (DEBUG_DOMAIN,
878 "Failed to RequestHandles: %s",
879 error ? error->message : "No error given");
880 g_clear_error (&error);
883 handle = g_array_index (handles, guint, 0);
884 g_array_free (handles, TRUE);
886 if (!tp_conn_request_channel (DBUS_G_PROXY (priv->tp_conn),
887 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
888 TP_HANDLE_TYPE_GROUP,
893 empathy_debug (DEBUG_DOMAIN,
894 "Failed to RequestChannel: %s",
895 error ? error->message : "No error given");
896 g_clear_error (&error);
900 tp_contact_list_newchannel_cb (DBUS_G_PROXY (priv->tp_conn),
902 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
903 TP_HANDLE_TYPE_GROUP,
906 g_free (object_path);
908 return tp_contact_list_find_group (list, group);
912 tp_contact_list_add_to_group (EmpathyContactList *list,
913 EmpathyContact *contact,
916 EmpathyTpGroup *tp_group;
918 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
920 tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
923 empathy_tp_group_add_member (tp_group, contact, "");
927 tp_contact_list_remove_from_group (EmpathyContactList *list,
928 EmpathyContact *contact,
931 EmpathyTpGroup *tp_group;
933 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
935 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
939 empathy_tp_group_remove_member (tp_group, contact, "");
944 tp_contact_list_rename_group (EmpathyContactList *list,
945 const gchar *old_group,
946 const gchar *new_group)
948 EmpathyTpGroup *tp_group;
951 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
953 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
959 empathy_debug (DEBUG_DOMAIN, "rename group %s to %s", old_group, new_group);
961 /* Remove all members from the old group */
962 members = empathy_tp_group_get_members (tp_group);
963 empathy_tp_group_remove_members (tp_group, members, "");
964 empathy_tp_group_close (tp_group);
966 /* Add all members to the new group */
967 tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
969 empathy_tp_group_add_members (tp_group, members, "");
971 g_list_foreach (members, (GFunc) g_object_unref, NULL);
972 g_list_free (members);
976 tp_contact_list_iface_init (EmpathyContactListIface *iface)
978 iface->add = tp_contact_list_add;
979 iface->remove = tp_contact_list_remove;
980 iface->get_members = tp_contact_list_get_members;
981 iface->get_pendings = tp_contact_list_get_pendings;
982 iface->get_all_groups = tp_contact_list_get_all_groups;
983 iface->get_groups = tp_contact_list_get_groups;
984 iface->add_to_group = tp_contact_list_add_to_group;
985 iface->remove_from_group = tp_contact_list_remove_from_group;
986 iface->rename_group = tp_contact_list_rename_group;