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-lib.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-utils.h"
38 #define DEBUG_FLAG EMPATHY_DEBUG_TP | EMPATHY_DEBUG_CONTACT
39 #include "empathy-debug.h"
41 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpContactList)
43 TpConnection *connection;
44 const gchar *protocol_group;
47 EmpathyTpGroup *publish;
48 EmpathyTpGroup *subscribe;
53 GHashTable *contacts_groups;
54 } EmpathyTpContactListPriv;
57 TP_CONTACT_LIST_TYPE_PUBLISH,
58 TP_CONTACT_LIST_TYPE_SUBSCRIBE,
59 TP_CONTACT_LIST_TYPE_UNKNOWN
62 static void tp_contact_list_iface_init (EmpathyContactListIface *iface);
69 G_DEFINE_TYPE_WITH_CODE (EmpathyTpContactList, empathy_tp_contact_list, G_TYPE_OBJECT,
70 G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST,
71 tp_contact_list_iface_init));
74 tp_contact_list_group_destroy_cb (EmpathyTpGroup *group,
75 EmpathyTpContactList *list)
77 EmpathyTpContactListPriv *priv = GET_PRIV (list);
79 DEBUG ("Group destroyed: %s", empathy_tp_group_get_name (group));
81 priv->groups = g_list_remove (priv->groups, group);
82 g_object_unref (group);
86 tp_contact_list_group_member_added_cb (EmpathyTpGroup *group,
87 EmpathyContact *contact,
88 EmpathyContact *actor,
91 EmpathyTpContactList *list)
93 EmpathyTpContactListPriv *priv = GET_PRIV (list);
94 const gchar *group_name;
97 if (!g_list_find (priv->members, contact)) {
101 groups = g_hash_table_lookup (priv->contacts_groups, contact);
103 groups = g_slice_new0 (GList*);
104 g_hash_table_insert (priv->contacts_groups,
105 g_object_ref (contact),
109 group_name = empathy_tp_group_get_name (group);
110 if (!g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp)) {
111 DEBUG ("Contact %s (%d) added to group %s",
112 empathy_contact_get_id (contact),
113 empathy_contact_get_handle (contact),
115 *groups = g_list_prepend (*groups, g_strdup (group_name));
116 g_signal_emit_by_name (list, "groups-changed", contact,
123 tp_contact_list_group_member_removed_cb (EmpathyTpGroup *group,
124 EmpathyContact *contact,
125 EmpathyContact *actor,
127 const gchar *message,
128 EmpathyTpContactList *list)
130 EmpathyTpContactListPriv *priv = GET_PRIV (list);
131 const gchar *group_name;
134 if (!g_list_find (priv->members, contact)) {
138 groups = g_hash_table_lookup (priv->contacts_groups, contact);
143 group_name = empathy_tp_group_get_name (group);
144 if ((l = g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp))) {
145 DEBUG ("Contact %s (%d) removed from group %s",
146 empathy_contact_get_id (contact),
147 empathy_contact_get_handle (contact),
150 *groups = g_list_delete_link (*groups, l);
151 g_signal_emit_by_name (list, "groups-changed", contact,
157 static EmpathyTpGroup *
158 tp_contact_list_find_group (EmpathyTpContactList *list,
161 EmpathyTpContactListPriv *priv = GET_PRIV (list);
164 for (l = priv->groups; l; l = l->next) {
165 if (!tp_strdiff (group, empathy_tp_group_get_name (l->data))) {
172 static TpContactListType
173 tp_contact_list_get_type (EmpathyTpContactList *list,
174 EmpathyTpGroup *group)
178 name = empathy_tp_group_get_name (group);
179 if (!tp_strdiff (name, "subscribe")) {
180 return TP_CONTACT_LIST_TYPE_SUBSCRIBE;
181 } else if (!tp_strdiff (name, "publish")) {
182 return TP_CONTACT_LIST_TYPE_PUBLISH;
185 return TP_CONTACT_LIST_TYPE_UNKNOWN;
189 tp_contact_list_add_member (EmpathyTpContactList *list,
190 EmpathyContact *contact,
191 EmpathyContact *actor,
193 const gchar *message)
195 EmpathyTpContactListPriv *priv = GET_PRIV (list);
198 /* Add to the list and emit signal */
199 priv->members = g_list_prepend (priv->members, g_object_ref (contact));
200 g_signal_emit_by_name (list, "members-changed",
201 contact, actor, reason, message,
204 /* This contact is now member, implicitly accept pending. */
205 if (g_list_find (priv->pendings, contact)) {
206 empathy_tp_group_add_member (priv->publish, contact, "");
209 /* Update groups of the contact */
210 for (l = priv->groups; l; l = l->next) {
211 if (empathy_tp_group_is_member (l->data, contact)) {
212 tp_contact_list_group_member_added_cb (l->data, contact,
220 tp_contact_list_added_cb (EmpathyTpGroup *group,
221 EmpathyContact *contact,
222 EmpathyContact *actor,
224 const gchar *message,
225 EmpathyTpContactList *list)
227 EmpathyTpContactListPriv *priv = GET_PRIV (list);
228 TpContactListType list_type;
230 list_type = tp_contact_list_get_type (list, group);
231 DEBUG ("Contact %s (%d) added to list type %d",
232 empathy_contact_get_id (contact),
233 empathy_contact_get_handle (contact),
236 /* We now get the presence of that contact, add it to members */
237 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
238 !g_list_find (priv->members, contact)) {
239 tp_contact_list_add_member (list, contact, actor, reason, message);
242 /* We now send our presence to that contact, remove it from pendings */
243 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
244 g_list_find (priv->pendings, contact)) {
245 g_signal_emit_by_name (list, "pendings-changed",
246 contact, actor, reason, message,
248 priv->pendings = g_list_remove (priv->pendings, contact);
249 g_object_unref (contact);
254 tp_contact_list_removed_cb (EmpathyTpGroup *group,
255 EmpathyContact *contact,
256 EmpathyContact *actor,
258 const gchar *message,
259 EmpathyTpContactList *list)
261 EmpathyTpContactListPriv *priv = GET_PRIV (list);
262 TpContactListType list_type;
264 list_type = tp_contact_list_get_type (list, group);
265 DEBUG ("Contact %s (%d) removed from list type %d",
266 empathy_contact_get_id (contact),
267 empathy_contact_get_handle (contact),
270 /* This contact refuses to send us his presence, remove from members. */
271 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
272 g_list_find (priv->members, contact)) {
273 g_signal_emit_by_name (list, "members-changed",
274 contact, actor, reason, message,
276 priv->members = g_list_remove (priv->members, contact);
277 g_object_unref (contact);
280 /* We refuse to send our presence to that contact, remove from pendings */
281 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
282 g_list_find (priv->pendings, contact)) {
283 g_signal_emit_by_name (list, "pendings-changed",
284 contact, actor, reason, message,
286 priv->pendings = g_list_remove (priv->pendings, contact);
287 g_object_unref (contact);
292 tp_contact_list_pending_cb (EmpathyTpGroup *group,
293 EmpathyContact *contact,
294 EmpathyContact *actor,
296 const gchar *message,
297 EmpathyTpContactList *list)
299 EmpathyTpContactListPriv *priv = GET_PRIV (list);
300 TpContactListType list_type;
302 list_type = tp_contact_list_get_type (list, group);
303 DEBUG ("Contact %s (%d) pending in list type %d",
304 empathy_contact_get_id (contact),
305 empathy_contact_get_handle (contact),
308 /* We want this contact in our contact list but we don't get its
309 * presence yet. Add to members anyway. */
310 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
311 !g_list_find (priv->members, contact)) {
312 tp_contact_list_add_member (list, contact, actor, reason, message);
315 /* This contact wants our presence, auto accept if he is member,
316 * otherwise he is pending. */
317 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
318 !g_list_find (priv->pendings, contact)) {
319 if (g_list_find (priv->members, contact)) {
320 empathy_tp_group_add_member (priv->publish, contact, "");
322 priv->pendings = g_list_prepend (priv->pendings,
323 g_object_ref (contact));
324 g_signal_emit_by_name (list, "pendings-changed",
325 contact, actor, reason, message,
332 tp_contact_list_group_list_free (GList **groups)
334 g_list_foreach (*groups, (GFunc) g_free, NULL);
335 g_list_free (*groups);
336 g_slice_free (GList*, groups);
340 tp_contact_list_add_channel (EmpathyTpContactList *list,
341 const gchar *object_path,
342 const gchar *channel_type,
343 TpHandleType handle_type,
346 EmpathyTpContactListPriv *priv = GET_PRIV (list);
348 EmpathyTpGroup *group;
349 const gchar *group_name;
352 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) != 0 ||
353 handle_type != TP_HANDLE_TYPE_GROUP) {
357 channel = tp_channel_new (priv->connection,
358 object_path, channel_type,
359 handle_type, handle, NULL);
361 group = empathy_tp_group_new (channel);
362 empathy_run_until_ready (group);
363 g_object_unref (channel);
365 /* Check if already exists */
366 group_name = empathy_tp_group_get_name (group);
367 if (tp_contact_list_find_group (list, group_name)) {
368 g_object_unref (group);
373 DEBUG ("New server-side group: %s", group_name);
374 priv->groups = g_list_prepend (priv->groups, group);
375 g_signal_connect (group, "member-added",
376 G_CALLBACK (tp_contact_list_group_member_added_cb),
378 g_signal_connect (group, "member-removed",
379 G_CALLBACK (tp_contact_list_group_member_removed_cb),
381 g_signal_connect (group, "destroy",
382 G_CALLBACK (tp_contact_list_group_destroy_cb),
385 /* Get initial members */
386 contacts = empathy_tp_group_get_members (group);
387 for (l = contacts; l; l = l->next) {
388 tp_contact_list_group_member_added_cb (group, l->data,
391 g_object_unref (l->data);
393 g_list_free (contacts);
397 tp_contact_list_new_channel_cb (TpConnection *proxy,
398 const gchar *object_path,
399 const gchar *channel_type,
402 gboolean suppress_handler,
406 EmpathyTpContactListPriv *priv = GET_PRIV (list);
408 if (!suppress_handler && priv->ready) {
409 tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
410 object_path, channel_type,
411 handle_type, handle);
416 tp_contact_list_list_channels_cb (TpConnection *connection,
417 const GPtrArray *channels,
422 EmpathyTpContactListPriv *priv = GET_PRIV (list);
426 DEBUG ("Error: %s", error->message);
430 for (i = 0; i < channels->len; i++) {
431 GValueArray *chan_struct;
432 const gchar *object_path;
433 const gchar *channel_type;
434 TpHandleType handle_type;
437 chan_struct = g_ptr_array_index (channels, i);
438 object_path = g_value_get_boxed (g_value_array_get_nth (chan_struct, 0));
439 channel_type = g_value_get_string (g_value_array_get_nth (chan_struct, 1));
440 handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2));
441 handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3));
443 tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
444 object_path, channel_type,
445 handle_type, handle);
452 tp_contact_list_request_channel_cb (TpConnection *connection,
453 const gchar *object_path,
456 GObject *weak_object)
458 EmpathyTpContactList *list = EMPATHY_TP_CONTACT_LIST (weak_object);
459 EmpathyTpContactListPriv *priv = GET_PRIV (list);
460 EmpathyTpGroup *group;
462 TpContactListType list_type;
466 DEBUG ("Error: %s", error->message);
470 channel = tp_channel_new (connection, object_path,
471 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
473 GPOINTER_TO_UINT (user_data),
475 group = empathy_tp_group_new (channel);
476 empathy_run_until_ready (group);
478 list_type = tp_contact_list_get_type (list, group);
479 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && !priv->publish) {
480 DEBUG ("Got publish list");
481 priv->publish = group;
483 /* Publish is the list of contacts to who we send our
484 * presence. Makes no sense to be in remote-pending */
485 g_signal_connect (group, "local-pending",
486 G_CALLBACK (tp_contact_list_pending_cb),
489 contacts = empathy_tp_group_get_local_pendings (group);
490 for (l = contacts; l; l = l->next) {
491 EmpathyPendingInfo *info = l->data;
492 tp_contact_list_pending_cb (group,
498 empathy_pending_info_free (info);
500 g_list_free (contacts);
502 else if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && !priv->subscribe) {
503 DEBUG ("Got subscribe list");
504 priv->subscribe = group;
506 /* Subscribe is the list of contacts from who we
507 * receive presence. Makes no sense to be in
509 g_signal_connect (group, "remote-pending",
510 G_CALLBACK (tp_contact_list_pending_cb),
513 contacts = empathy_tp_group_get_remote_pendings (group);
514 for (l = contacts; l; l = l->next) {
515 tp_contact_list_pending_cb (group,
519 g_object_unref (l->data);
521 g_list_free (contacts);
523 DEBUG ("Type of contact list channel unknown or aleady "
524 "have that list: %s",
525 empathy_tp_group_get_name (group));
526 g_object_unref (group);
530 /* For all list types when need to get members */
531 g_signal_connect (group, "member-added",
532 G_CALLBACK (tp_contact_list_added_cb),
534 g_signal_connect (group, "member-removed",
535 G_CALLBACK (tp_contact_list_removed_cb),
538 contacts = empathy_tp_group_get_members (group);
539 for (l = contacts; l; l = l->next) {
540 tp_contact_list_added_cb (group,
544 g_object_unref (l->data);
546 g_list_free (contacts);
550 tp_contact_list_request_handle_cb (TpConnection *connection,
551 const GArray *handles,
559 DEBUG ("Error: %s", error->message);
563 handle = g_array_index (handles, guint, 0);
564 tp_cli_connection_call_request_channel (connection, -1,
565 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
569 tp_contact_list_request_channel_cb,
570 GUINT_TO_POINTER (handle), NULL,
575 tp_contact_list_request_list (EmpathyTpContactList *list,
578 EmpathyTpContactListPriv *priv = GET_PRIV (list);
579 const gchar *names[] = {type, NULL};
581 tp_cli_connection_call_request_handles (priv->connection,
585 tp_contact_list_request_handle_cb,
591 tp_contact_list_finalize (GObject *object)
593 EmpathyTpContactListPriv *priv;
594 EmpathyTpContactList *list;
596 list = EMPATHY_TP_CONTACT_LIST (object);
597 priv = GET_PRIV (list);
599 DEBUG ("finalize: %p", object);
601 if (priv->subscribe) {
602 g_object_unref (priv->subscribe);
605 g_object_unref (priv->publish);
608 if (priv->connection) {
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_constructed (GObject *list)
627 EmpathyTpContactListPriv *priv = GET_PRIV (list);
628 const gchar *protocol_name = NULL;
630 tp_contact_list_request_list (EMPATHY_TP_CONTACT_LIST (list), "publish");
631 tp_contact_list_request_list (EMPATHY_TP_CONTACT_LIST (list), "subscribe");
633 tp_cli_connection_call_list_channels (priv->connection, -1,
634 tp_contact_list_list_channels_cb,
638 tp_cli_connection_connect_to_new_channel (priv->connection,
639 tp_contact_list_new_channel_cb,
643 /* Check for protocols that does not support contact groups. We can
644 * put all contacts into a special group in that case.
645 * FIXME: Default group should be an information in the profile */
646 //protocol_name = tp_connection_get_protocol (priv->connection);
647 if (!tp_strdiff (protocol_name, "local-xmpp") == 0) {
648 priv->protocol_group = _("People nearby");
653 tp_contact_list_get_property (GObject *object,
658 EmpathyTpContactListPriv *priv = GET_PRIV (object);
661 case PROP_CONNECTION:
662 g_value_set_object (value, priv->connection);
665 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
671 tp_contact_list_set_property (GObject *object,
676 EmpathyTpContactListPriv *priv = GET_PRIV (object);
679 case PROP_CONNECTION:
680 priv->connection = g_value_dup_object (value);
683 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
689 empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass)
691 GObjectClass *object_class = G_OBJECT_CLASS (klass);
693 object_class->finalize = tp_contact_list_finalize;
694 object_class->constructed = tp_contact_list_constructed;
695 object_class->get_property = tp_contact_list_get_property;
696 object_class->set_property = tp_contact_list_set_property;
698 g_object_class_install_property (object_class,
700 g_param_spec_object ("connection",
702 "The connection associated with the contact list",
705 G_PARAM_CONSTRUCT_ONLY));
707 g_type_class_add_private (object_class, sizeof (EmpathyTpContactListPriv));
711 empathy_tp_contact_list_init (EmpathyTpContactList *list)
713 EmpathyTpContactListPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (list,
714 EMPATHY_TYPE_TP_CONTACT_LIST, EmpathyTpContactListPriv);
717 priv->contacts_groups = g_hash_table_new_full (g_direct_hash,
719 (GDestroyNotify) g_object_unref,
720 (GDestroyNotify) tp_contact_list_group_list_free);
723 EmpathyTpContactList *
724 empathy_tp_contact_list_new (TpConnection *connection)
726 return g_object_new (EMPATHY_TYPE_TP_CONTACT_LIST,
727 "connection", connection,
732 empathy_tp_contact_list_get_connection (EmpathyTpContactList *list)
734 EmpathyTpContactListPriv *priv;
736 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
738 priv = GET_PRIV (list);
740 return priv->connection;
744 tp_contact_list_add (EmpathyContactList *list,
745 EmpathyContact *contact,
746 const gchar *message)
748 EmpathyTpContactListPriv *priv = GET_PRIV (list);
750 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
752 if (priv->subscribe) {
753 empathy_tp_group_add_member (priv->subscribe, contact, message);
756 if (priv->publish && g_list_find (priv->pendings, contact)) {
757 empathy_tp_group_add_member (priv->publish, contact, message);
762 tp_contact_list_remove (EmpathyContactList *list,
763 EmpathyContact *contact,
764 const gchar *message)
766 EmpathyTpContactListPriv *priv = GET_PRIV (list);
768 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
770 if (priv->subscribe) {
771 empathy_tp_group_remove_member (priv->subscribe, contact, message);
774 empathy_tp_group_remove_member (priv->publish, contact, message);
779 tp_contact_list_get_members (EmpathyContactList *list)
781 EmpathyTpContactListPriv *priv = GET_PRIV (list);
783 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
785 g_list_foreach (priv->members, (GFunc) g_object_ref, NULL);
786 return g_list_copy (priv->members);
790 tp_contact_list_get_pendings (EmpathyContactList *list)
792 EmpathyTpContactListPriv *priv = GET_PRIV (list);
794 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
796 g_list_foreach (priv->pendings, (GFunc) g_object_ref, NULL);
797 return g_list_copy (priv->pendings);
801 tp_contact_list_get_all_groups (EmpathyContactList *list)
803 EmpathyTpContactListPriv *priv = GET_PRIV (list);
804 GList *groups = NULL, *l;
806 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
808 if (priv->protocol_group) {
809 groups = g_list_prepend (groups, g_strdup (priv->protocol_group));
812 for (l = priv->groups; l; l = l->next) {
815 name = empathy_tp_group_get_name (l->data);
816 groups = g_list_prepend (groups, g_strdup (name));
823 tp_contact_list_get_groups (EmpathyContactList *list,
824 EmpathyContact *contact)
826 EmpathyTpContactListPriv *priv = GET_PRIV (list);
828 GList *ret = NULL, *l;
830 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
832 if (priv->protocol_group) {
833 ret = g_list_prepend (ret, g_strdup (priv->protocol_group));
836 groups = g_hash_table_lookup (priv->contacts_groups, contact);
841 for (l = *groups; l; l = l->next) {
842 ret = g_list_prepend (ret, g_strdup (l->data));
849 static EmpathyTpGroup *
850 tp_contact_list_get_group (EmpathyTpContactList *list,
853 EmpathyTpContactListPriv *priv = GET_PRIV (list);
854 EmpathyTpGroup *tp_group;
858 const char *names[2] = {group, NULL};
859 GError *error = NULL;
861 tp_group = tp_contact_list_find_group (list, group);
866 DEBUG ("creating new group: %s", group);
868 if (!tp_cli_connection_run_request_handles (priv->connection, -1,
869 TP_HANDLE_TYPE_GROUP,
873 DEBUG ("Failed to RequestHandles: %s",
874 error ? error->message : "No error given");
875 g_clear_error (&error);
878 handle = g_array_index (handles, guint, 0);
879 g_array_free (handles, TRUE);
881 if (!tp_cli_connection_run_request_channel (priv->connection, -1,
882 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
883 TP_HANDLE_TYPE_GROUP,
888 DEBUG ("Failed to RequestChannel: %s",
889 error ? error->message : "No error given");
890 g_clear_error (&error);
894 tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
896 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
897 TP_HANDLE_TYPE_GROUP, handle);
899 g_free (object_path);
901 return tp_contact_list_find_group (list, group);
905 tp_contact_list_add_to_group (EmpathyContactList *list,
906 EmpathyContact *contact,
909 EmpathyTpGroup *tp_group;
911 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
913 tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
917 empathy_tp_group_add_member (tp_group, contact, "");
922 tp_contact_list_remove_from_group (EmpathyContactList *list,
923 EmpathyContact *contact,
926 EmpathyTpGroup *tp_group;
928 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
930 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
934 empathy_tp_group_remove_member (tp_group, contact, "");
939 tp_contact_list_rename_group (EmpathyContactList *list,
940 const gchar *old_group,
941 const gchar *new_group)
943 EmpathyTpGroup *tp_group;
946 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
948 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
954 DEBUG ("rename group %s to %s", old_group, new_group);
956 /* Remove all members from the old group */
957 members = empathy_tp_group_get_members (tp_group);
958 empathy_tp_group_remove_members (tp_group, members, "");
959 empathy_tp_group_close (tp_group);
961 /* Add all members to the new group */
962 tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
964 empathy_tp_group_add_members (tp_group, members, "");
966 g_list_foreach (members, (GFunc) g_object_unref, NULL);
967 g_list_free (members);
971 tp_contact_list_remove_group (EmpathyContactList *list,
974 EmpathyTpGroup *tp_group;
977 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
979 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
986 DEBUG ("remove group %s", group);
988 /* Remove all members of the group */
989 members = empathy_tp_group_get_members (tp_group);
990 empathy_tp_group_remove_members (tp_group, members, "");
991 empathy_tp_group_close (tp_group);
993 g_list_foreach (members, (GFunc) g_object_unref, NULL);
994 g_list_free (members);
998 tp_contact_list_iface_init (EmpathyContactListIface *iface)
1000 iface->add = tp_contact_list_add;
1001 iface->remove = tp_contact_list_remove;
1002 iface->get_members = tp_contact_list_get_members;
1003 iface->get_pendings = tp_contact_list_get_pendings;
1004 iface->get_all_groups = tp_contact_list_get_all_groups;
1005 iface->get_groups = tp_contact_list_get_groups;
1006 iface->add_to_group = tp_contact_list_add_to_group;
1007 iface->remove_from_group = tp_contact_list_remove_from_group;
1008 iface->rename_group = tp_contact_list_rename_group;
1009 iface->remove_group = tp_contact_list_remove_group;
1013 empathy_tp_contact_list_can_add (EmpathyTpContactList *list)
1015 EmpathyTpContactListPriv *priv;
1016 TpChannelGroupFlags flags;
1018 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), FALSE);
1020 priv = GET_PRIV (list);
1022 if (priv->subscribe == NULL)
1025 flags = empathy_tp_group_get_flags (priv->subscribe);
1026 return (flags & TP_CHANNEL_GROUP_FLAG_CAN_ADD) != 0;
1030 empathy_tp_contact_list_remove_all (EmpathyTpContactList *list)
1032 EmpathyTpContactListPriv *priv = GET_PRIV (list);
1035 /* Remove all contacts */
1036 for (l = priv->members; l; l = l->next) {
1037 g_signal_emit_by_name (list, "members-changed", l->data,
1040 g_object_unref (l->data);
1042 for (l = priv->pendings; l; l = l->next) {
1043 g_signal_emit_by_name (list, "pendings-changed", l->data,
1046 g_object_unref (l->data);
1048 g_list_free (priv->members);
1049 g_list_free (priv->pendings);
1050 priv->members = NULL;
1051 priv->pendings = NULL;