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-2008 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 <telepathy-glib/channel.h>
29 #include <telepathy-glib/connection.h>
30 #include <telepathy-glib/util.h>
31 #include <telepathy-glib/dbus.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 {
46 TpConnection *connection;
47 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);
79 static guint signals[LAST_SIGNAL];
81 G_DEFINE_TYPE_WITH_CODE (EmpathyTpContactList, empathy_tp_contact_list, G_TYPE_OBJECT,
82 G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST,
83 tp_contact_list_iface_init));
86 tp_contact_list_group_destroy_cb (EmpathyTpGroup *group,
87 EmpathyTpContactList *list)
89 EmpathyTpContactListPriv *priv = GET_PRIV (list);
91 empathy_debug (DEBUG_DOMAIN, "Group destroyed: %s",
92 empathy_tp_group_get_name (group));
94 priv->groups = g_list_remove (priv->groups, group);
95 g_object_unref (group);
99 tp_contact_list_group_member_added_cb (EmpathyTpGroup *group,
100 EmpathyContact *contact,
101 EmpathyContact *actor,
103 const gchar *message,
104 EmpathyTpContactList *list)
106 EmpathyTpContactListPriv *priv = GET_PRIV (list);
107 const gchar *group_name;
110 if (!g_list_find (priv->members, contact)) {
114 groups = g_hash_table_lookup (priv->contacts_groups, contact);
116 groups = g_slice_new0 (GList*);
117 g_hash_table_insert (priv->contacts_groups,
118 g_object_ref (contact),
122 group_name = empathy_tp_group_get_name (group);
123 if (!g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp)) {
124 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) added to group %s",
125 empathy_contact_get_id (contact),
126 empathy_contact_get_handle (contact),
128 *groups = g_list_prepend (*groups, g_strdup (group_name));
129 g_signal_emit_by_name (list, "groups-changed", contact,
136 tp_contact_list_group_member_removed_cb (EmpathyTpGroup *group,
137 EmpathyContact *contact,
138 EmpathyContact *actor,
140 const gchar *message,
141 EmpathyTpContactList *list)
143 EmpathyTpContactListPriv *priv = GET_PRIV (list);
144 const gchar *group_name;
147 if (!g_list_find (priv->members, contact)) {
151 groups = g_hash_table_lookup (priv->contacts_groups, contact);
156 group_name = empathy_tp_group_get_name (group);
157 if ((l = g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp))) {
158 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) removed from group %s",
159 empathy_contact_get_id (contact),
160 empathy_contact_get_handle (contact),
162 *groups = g_list_delete_link (*groups, l);
163 g_signal_emit_by_name (list, "groups-changed", contact,
169 static EmpathyTpGroup *
170 tp_contact_list_find_group (EmpathyTpContactList *list,
173 EmpathyTpContactListPriv *priv = GET_PRIV (list);
176 for (l = priv->groups; l; l = l->next) {
177 if (!tp_strdiff (group, empathy_tp_group_get_name (l->data))) {
184 static TpContactListType
185 tp_contact_list_get_type (EmpathyTpContactList *list,
186 EmpathyTpGroup *group)
190 name = empathy_tp_group_get_name (group);
191 if (!tp_strdiff (name, "subscribe")) {
192 return TP_CONTACT_LIST_TYPE_SUBSCRIBE;
193 } else if (!tp_strdiff (name, "publish")) {
194 return TP_CONTACT_LIST_TYPE_PUBLISH;
197 return TP_CONTACT_LIST_TYPE_UNKNOWN;
201 tp_contact_list_add_member (EmpathyTpContactList *list,
202 EmpathyContact *contact,
203 EmpathyContact *actor,
205 const gchar *message)
207 EmpathyTpContactListPriv *priv = GET_PRIV (list);
210 /* Add to the list and emit signal */
211 priv->members = g_list_prepend (priv->members, g_object_ref (contact));
212 g_signal_emit_by_name (list, "members-changed",
213 contact, actor, reason, message,
216 /* This contact is now member, implicitly accept pending. */
217 if (g_list_find (priv->pendings, contact)) {
218 empathy_tp_group_add_member (priv->publish, contact, "");
221 /* Update groups of the contact */
222 for (l = priv->groups; l; l = l->next) {
223 if (empathy_tp_group_is_member (l->data, contact)) {
224 tp_contact_list_group_member_added_cb (l->data, contact,
232 tp_contact_list_added_cb (EmpathyTpGroup *group,
233 EmpathyContact *contact,
234 EmpathyContact *actor,
236 const gchar *message,
237 EmpathyTpContactList *list)
239 EmpathyTpContactListPriv *priv = GET_PRIV (list);
240 TpContactListType list_type;
242 list_type = tp_contact_list_get_type (list, group);
243 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) added to list type %d",
244 empathy_contact_get_id (contact),
245 empathy_contact_get_handle (contact),
248 /* We now get the presence of that contact, add it to members */
249 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
250 !g_list_find (priv->members, contact)) {
251 tp_contact_list_add_member (list, contact, actor, reason, message);
254 /* We now send our presence to that contact, remove it from pendings */
255 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
256 g_list_find (priv->pendings, contact)) {
257 g_signal_emit_by_name (list, "pendings-changed",
258 contact, actor, reason, message,
260 priv->pendings = g_list_remove (priv->pendings, contact);
261 g_object_unref (contact);
266 tp_contact_list_removed_cb (EmpathyTpGroup *group,
267 EmpathyContact *contact,
268 EmpathyContact *actor,
270 const gchar *message,
271 EmpathyTpContactList *list)
273 EmpathyTpContactListPriv *priv = GET_PRIV (list);
274 TpContactListType list_type;
276 list_type = tp_contact_list_get_type (list, group);
277 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) removed from list type %d",
278 empathy_contact_get_id (contact),
279 empathy_contact_get_handle (contact),
282 /* This contact refuses to send us his presence, remove from members. */
283 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
284 g_list_find (priv->members, contact)) {
285 g_signal_emit_by_name (list, "members-changed",
286 contact, actor, reason, message,
288 priv->members = g_list_remove (priv->members, contact);
289 g_object_unref (contact);
292 /* We refuse to send our presence to that contact, remove from pendings */
293 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
294 g_list_find (priv->pendings, contact)) {
295 g_signal_emit_by_name (list, "pendings-changed",
296 contact, actor, reason, message,
298 priv->pendings = g_list_remove (priv->pendings, contact);
299 g_object_unref (contact);
304 tp_contact_list_pending_cb (EmpathyTpGroup *group,
305 EmpathyContact *contact,
306 EmpathyContact *actor,
308 const gchar *message,
309 EmpathyTpContactList *list)
311 EmpathyTpContactListPriv *priv = GET_PRIV (list);
312 TpContactListType list_type;
314 list_type = tp_contact_list_get_type (list, group);
315 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) pending in list type %d",
316 empathy_contact_get_id (contact),
317 empathy_contact_get_handle (contact),
320 /* We want this contact in our contact list but we don't get its
321 * presence yet. Add to members anyway. */
322 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
323 !g_list_find (priv->members, contact)) {
324 tp_contact_list_add_member (list, contact, actor, reason, message);
327 /* This contact wants our presence, auto accept if he is member,
328 * otherwise he is pending. */
329 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
330 !g_list_find (priv->pendings, contact)) {
331 if (g_list_find (priv->members, contact)) {
332 empathy_tp_group_add_member (priv->publish, contact, "");
334 priv->pendings = g_list_prepend (priv->pendings,
335 g_object_ref (contact));
336 g_signal_emit_by_name (list, "pendings-changed",
337 contact, actor, reason, message,
344 tp_contact_list_invalidated_cb (TpConnection *connection,
348 EmpathyTpContactList *list)
350 EmpathyTpContactListPriv *priv = GET_PRIV (list);
353 empathy_debug (DEBUG_DOMAIN, "Connection invalidated");
355 /* Remove all contacts */
356 for (l = priv->members; l; l = l->next) {
357 g_signal_emit_by_name (list, "members-changed", l->data,
360 g_object_unref (l->data);
362 for (l = priv->pendings; l; l = l->next) {
363 g_signal_emit_by_name (list, "pendings-changed", l->data,
366 g_object_unref (l->data);
368 g_list_free (priv->members);
369 g_list_free (priv->pendings);
370 priv->members = NULL;
371 priv->pendings = NULL;
373 /* Tell the world to not use us anymore */
374 g_signal_emit (list, signals[DESTROY], 0);
378 tp_contact_list_group_list_free (GList **groups)
380 g_list_foreach (*groups, (GFunc) g_free, NULL);
381 g_list_free (*groups);
382 g_slice_free (GList*, groups);
386 tp_contact_list_add_channel (EmpathyTpContactList *list,
387 const gchar *object_path,
388 const gchar *channel_type,
389 TpHandleType handle_type,
392 EmpathyTpContactListPriv *priv = GET_PRIV (list);
393 EmpathyTpGroup *group;
396 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) != 0 ||
397 (handle_type != TP_HANDLE_TYPE_LIST &&
398 handle_type != TP_HANDLE_TYPE_GROUP)) {
402 channel = tp_channel_new (priv->connection,
403 object_path, channel_type,
404 handle_type, handle, NULL);
406 group = empathy_tp_group_new (channel);
407 empathy_run_until_ready (group);
408 g_object_unref (channel);
410 if (handle_type == TP_HANDLE_TYPE_LIST) {
411 TpContactListType list_type;
414 list_type = tp_contact_list_get_type (list, group);
415 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && !priv->publish) {
416 priv->publish = g_object_ref (group);
418 /* Publish is the list of contacts to who we send our
419 * presence. Makes no sense to be in remote-pending */
420 g_signal_connect (group, "local-pending",
421 G_CALLBACK (tp_contact_list_pending_cb),
424 contacts = empathy_tp_group_get_local_pendings (group);
425 for (l = contacts; l; l = l->next) {
426 EmpathyPendingInfo *info = l->data;
428 tp_contact_list_pending_cb (group,
434 empathy_pending_info_free (info);
436 g_list_free (contacts);
438 else if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && !priv->subscribe) {
439 priv->subscribe = g_object_ref (group);
441 /* Subscribe is the list of contacts from who we
442 * receive presence. Makes no sense to be in
444 g_signal_connect (group, "remote-pending",
445 G_CALLBACK (tp_contact_list_pending_cb),
448 contacts = empathy_tp_group_get_remote_pendings (group);
449 for (l = contacts; l; l = l->next) {
450 tp_contact_list_pending_cb (group,
454 g_object_unref (l->data);
456 g_list_free (contacts);
458 empathy_debug (DEBUG_DOMAIN,
459 "Type of contact list channel unknown "
460 "or aleady have that list: %s",
461 empathy_tp_group_get_name (group));
464 empathy_debug (DEBUG_DOMAIN,
465 "New contact list channel of type: %d",
468 g_signal_connect (group, "member-added",
469 G_CALLBACK (tp_contact_list_added_cb),
471 g_signal_connect (group, "member-removed",
472 G_CALLBACK (tp_contact_list_removed_cb),
475 contacts = empathy_tp_group_get_members (group);
476 for (l = contacts; l; l = l->next) {
477 tp_contact_list_added_cb (group,
481 g_object_unref (l->data);
483 g_list_free (contacts);
485 else if (handle_type == TP_HANDLE_TYPE_GROUP) {
486 const gchar *group_name;
489 /* Check if already exists */
490 group_name = empathy_tp_group_get_name (group);
491 if (tp_contact_list_find_group (list, group_name)) {
495 empathy_debug (DEBUG_DOMAIN, "New server-side group channel: %s",
498 priv->groups = g_list_prepend (priv->groups, g_object_ref (group));
500 g_signal_connect (group, "member-added",
501 G_CALLBACK (tp_contact_list_group_member_added_cb),
503 g_signal_connect (group, "member-removed",
504 G_CALLBACK (tp_contact_list_group_member_removed_cb),
506 g_signal_connect (group, "destroy",
507 G_CALLBACK (tp_contact_list_group_destroy_cb),
510 contacts = empathy_tp_group_get_members (group);
511 for (l = contacts; l; l = l->next) {
512 tp_contact_list_group_member_added_cb (group, l->data,
515 g_object_unref (l->data);
517 g_list_free (contacts);
519 empathy_debug (DEBUG_DOMAIN,
520 "Unknown handle type (%d) for contact list channel",
525 g_object_unref (group);
529 tp_contact_list_new_channel_cb (TpConnection *proxy,
530 const gchar *object_path,
531 const gchar *channel_type,
534 gboolean suppress_handler,
538 EmpathyTpContactListPriv *priv = GET_PRIV (list);
540 if (!suppress_handler && priv->ready) {
541 tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
542 object_path, channel_type,
543 handle_type, handle);
548 tp_contact_list_list_channels_cb (TpConnection *connection,
549 const GPtrArray *channels,
554 EmpathyTpContactListPriv *priv = GET_PRIV (list);
558 empathy_debug (DEBUG_DOMAIN,
559 "Failed to get list of open channels: %s",
560 error ? error->message : "No error given");
564 for (i = 0; i < channels->len; i++) {
565 GValueArray *chan_struct;
566 const gchar *object_path;
567 const gchar *channel_type;
568 TpHandleType handle_type;
571 chan_struct = g_ptr_array_index (channels, i);
572 object_path = g_value_get_boxed (g_value_array_get_nth (chan_struct, 0));
573 channel_type = g_value_get_string (g_value_array_get_nth (chan_struct, 1));
574 handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2));
575 handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3));
577 tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
578 object_path, channel_type,
579 handle_type, handle);
586 tp_contact_list_finalize (GObject *object)
588 EmpathyTpContactListPriv *priv;
589 EmpathyTpContactList *list;
591 list = EMPATHY_TP_CONTACT_LIST (object);
592 priv = GET_PRIV (list);
594 empathy_debug (DEBUG_DOMAIN, "finalize: %p", object);
596 if (priv->subscribe) {
597 g_object_unref (priv->subscribe);
600 g_object_unref (priv->publish);
603 g_object_unref (priv->account);
605 if (priv->connection) {
606 g_signal_handlers_disconnect_by_func (priv->connection,
607 tp_contact_list_invalidated_cb,
609 g_object_unref (priv->connection);
612 g_hash_table_destroy (priv->contacts_groups);
613 g_list_foreach (priv->groups, (GFunc) g_object_unref, NULL);
614 g_list_free (priv->groups);
615 g_list_foreach (priv->members, (GFunc) g_object_unref, NULL);
616 g_list_free (priv->members);
617 g_list_foreach (priv->pendings, (GFunc) g_object_unref, NULL);
618 g_list_free (priv->pendings);
620 G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object);
624 tp_contact_list_ready_cb (EmpathyTpContactList *list)
626 EmpathyTpContactListPriv *priv = GET_PRIV (list);
628 tp_cli_connection_call_list_channels (priv->connection, -1,
629 tp_contact_list_list_channels_cb,
633 tp_cli_connection_connect_to_new_channel (priv->connection,
634 tp_contact_list_new_channel_cb,
636 G_OBJECT (list), NULL);
640 tp_contact_list_constructed (GObject *list)
643 EmpathyTpContactListPriv *priv = GET_PRIV (list);
648 const gchar *protocol_name;
650 /* Get the connection. status==0 means CONNECTED */
651 mc = empathy_mission_control_new ();
652 status = mission_control_get_connection_status (mc, priv->account, NULL);
653 g_return_if_fail (status == 0);
654 priv->connection = mission_control_get_tpconnection (mc, priv->account, NULL);
655 g_return_if_fail (priv->connection != NULL);
658 g_signal_connect (priv->connection, "invalidated",
659 G_CALLBACK (tp_contact_list_invalidated_cb),
661 g_object_get (priv->connection, "connection-ready", &ready, NULL);
663 tp_contact_list_ready_cb (EMPATHY_TP_CONTACT_LIST (list));
665 g_signal_connect_swapped (priv->connection, "connection-ready",
666 G_CALLBACK (tp_contact_list_ready_cb),
670 /* Check for protocols that does not support contact groups. We can
671 * put all contacts into a special group in that case.
672 * FIXME: Default group should be an information in the profile */
673 profile = mc_account_get_profile (priv->account);
674 protocol_name = mc_profile_get_protocol_name (profile);
675 if (strcmp (protocol_name, "local-xmpp") == 0) {
676 priv->protocol_group = _("People nearby");
678 g_object_unref (profile);
682 tp_contact_list_get_property (GObject *object,
687 EmpathyTpContactListPriv *priv = GET_PRIV (object);
691 g_value_set_object (value, priv->account);
694 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
700 tp_contact_list_set_property (GObject *object,
705 EmpathyTpContactListPriv *priv = GET_PRIV (object);
709 priv->account = g_object_ref (g_value_get_object (value));
712 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
718 empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass)
720 GObjectClass *object_class = G_OBJECT_CLASS (klass);
722 object_class->finalize = tp_contact_list_finalize;
723 object_class->constructed = tp_contact_list_constructed;
724 object_class->get_property = tp_contact_list_get_property;
725 object_class->set_property = tp_contact_list_set_property;
727 g_object_class_install_property (object_class,
729 g_param_spec_object ("account",
731 "The account associated with the contact list",
734 G_PARAM_CONSTRUCT_ONLY));
737 g_signal_new ("destroy",
738 G_TYPE_FROM_CLASS (klass),
742 g_cclosure_marshal_VOID__VOID,
746 g_type_class_add_private (object_class, sizeof (EmpathyTpContactListPriv));
750 empathy_tp_contact_list_init (EmpathyTpContactList *list)
752 EmpathyTpContactListPriv *priv = GET_PRIV (list);
754 priv->contacts_groups = g_hash_table_new_full (g_direct_hash,
756 (GDestroyNotify) g_object_unref,
757 (GDestroyNotify) tp_contact_list_group_list_free);
760 EmpathyTpContactList *
761 empathy_tp_contact_list_new (McAccount *account)
763 return g_object_new (EMPATHY_TYPE_TP_CONTACT_LIST,
769 empathy_tp_contact_list_get_account (EmpathyTpContactList *list)
771 EmpathyTpContactListPriv *priv;
773 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
775 priv = GET_PRIV (list);
777 return priv->account;
781 tp_contact_list_add (EmpathyContactList *list,
782 EmpathyContact *contact,
783 const gchar *message)
785 EmpathyTpContactListPriv *priv = GET_PRIV (list);
787 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
789 empathy_tp_group_add_member (priv->subscribe, contact, message);
790 if (g_list_find (priv->pendings, contact)) {
791 empathy_tp_group_add_member (priv->publish, contact, message);
796 tp_contact_list_remove (EmpathyContactList *list,
797 EmpathyContact *contact,
798 const gchar *message)
800 EmpathyTpContactListPriv *priv = GET_PRIV (list);
802 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
804 empathy_tp_group_remove_member (priv->subscribe, contact, message);
805 empathy_tp_group_remove_member (priv->publish, contact, message);
809 tp_contact_list_get_members (EmpathyContactList *list)
811 EmpathyTpContactListPriv *priv = GET_PRIV (list);
813 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
815 g_list_foreach (priv->members, (GFunc) g_object_ref, NULL);
816 return g_list_copy (priv->members);
820 tp_contact_list_get_pendings (EmpathyContactList *list)
822 EmpathyTpContactListPriv *priv = GET_PRIV (list);
824 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
826 g_list_foreach (priv->pendings, (GFunc) g_object_ref, NULL);
827 return g_list_copy (priv->pendings);
831 tp_contact_list_get_all_groups (EmpathyContactList *list)
833 EmpathyTpContactListPriv *priv = GET_PRIV (list);
834 GList *groups = NULL, *l;
836 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
838 if (priv->protocol_group) {
839 groups = g_list_prepend (groups, g_strdup (priv->protocol_group));
842 for (l = priv->groups; l; l = l->next) {
845 name = empathy_tp_group_get_name (l->data);
846 groups = g_list_prepend (groups, g_strdup (name));
853 tp_contact_list_get_groups (EmpathyContactList *list,
854 EmpathyContact *contact)
856 EmpathyTpContactListPriv *priv = GET_PRIV (list);
858 GList *ret = NULL, *l;
860 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
862 if (priv->protocol_group) {
863 ret = g_list_prepend (ret, g_strdup (priv->protocol_group));
866 groups = g_hash_table_lookup (priv->contacts_groups, contact);
871 for (l = *groups; l; l = l->next) {
872 ret = g_list_prepend (ret, g_strdup (l->data));
879 static EmpathyTpGroup *
880 tp_contact_list_get_group (EmpathyTpContactList *list,
883 EmpathyTpContactListPriv *priv = GET_PRIV (list);
884 EmpathyTpGroup *tp_group;
888 const char *names[2] = {group, NULL};
889 GError *error = NULL;
891 tp_group = tp_contact_list_find_group (list, group);
896 empathy_debug (DEBUG_DOMAIN, "creating new group: %s", group);
898 if (!tp_cli_connection_run_request_handles (priv->connection, -1,
899 TP_HANDLE_TYPE_GROUP,
903 empathy_debug (DEBUG_DOMAIN,
904 "Failed to RequestHandles: %s",
905 error ? error->message : "No error given");
906 g_clear_error (&error);
909 handle = g_array_index (handles, guint, 0);
910 g_array_free (handles, TRUE);
912 if (!tp_cli_connection_run_request_channel (priv->connection, -1,
913 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
914 TP_HANDLE_TYPE_GROUP,
919 empathy_debug (DEBUG_DOMAIN,
920 "Failed to RequestChannel: %s",
921 error ? error->message : "No error given");
922 g_clear_error (&error);
926 tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
928 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
929 TP_HANDLE_TYPE_GROUP, handle);
931 g_free (object_path);
933 return tp_contact_list_find_group (list, group);
937 tp_contact_list_add_to_group (EmpathyContactList *list,
938 EmpathyContact *contact,
941 EmpathyTpGroup *tp_group;
943 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
945 tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
948 empathy_tp_group_add_member (tp_group, contact, "");
952 tp_contact_list_remove_from_group (EmpathyContactList *list,
953 EmpathyContact *contact,
956 EmpathyTpGroup *tp_group;
958 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
960 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
964 empathy_tp_group_remove_member (tp_group, contact, "");
969 tp_contact_list_rename_group (EmpathyContactList *list,
970 const gchar *old_group,
971 const gchar *new_group)
973 EmpathyTpGroup *tp_group;
976 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
978 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
984 empathy_debug (DEBUG_DOMAIN, "rename group %s to %s", old_group, new_group);
986 /* Remove all members from the old group */
987 members = empathy_tp_group_get_members (tp_group);
988 empathy_tp_group_remove_members (tp_group, members, "");
989 empathy_tp_group_close (tp_group);
991 /* Add all members to the new group */
992 tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
994 empathy_tp_group_add_members (tp_group, members, "");
996 g_list_foreach (members, (GFunc) g_object_unref, NULL);
997 g_list_free (members);
1001 tp_contact_list_remove_group (EmpathyContactList *list,
1004 EmpathyTpGroup *tp_group;
1007 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
1009 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
1016 empathy_debug (DEBUG_DOMAIN, "remove group %s", group);
1018 /* Remove all members of the group */
1019 members = empathy_tp_group_get_members (tp_group);
1020 empathy_tp_group_remove_members (tp_group, members, "");
1021 empathy_tp_group_close (tp_group);
1023 g_list_foreach (members, (GFunc) g_object_unref, NULL);
1024 g_list_free (members);
1028 tp_contact_list_iface_init (EmpathyContactListIface *iface)
1030 iface->add = tp_contact_list_add;
1031 iface->remove = tp_contact_list_remove;
1032 iface->get_members = tp_contact_list_get_members;
1033 iface->get_pendings = tp_contact_list_get_pendings;
1034 iface->get_all_groups = tp_contact_list_get_all_groups;
1035 iface->get_groups = tp_contact_list_get_groups;
1036 iface->add_to_group = tp_contact_list_add_to_group;
1037 iface->remove_from_group = tp_contact_list_remove_from_group;
1038 iface->rename_group = tp_contact_list_rename_group;
1039 iface->remove_group = tp_contact_list_remove_group;