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)
44 TpConnection *connection;
45 const gchar *protocol_group;
48 EmpathyTpGroup *publish;
49 EmpathyTpGroup *subscribe;
54 GHashTable *contacts_groups;
55 } EmpathyTpContactListPriv;
58 TP_CONTACT_LIST_TYPE_PUBLISH,
59 TP_CONTACT_LIST_TYPE_SUBSCRIBE,
60 TP_CONTACT_LIST_TYPE_UNKNOWN
63 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 DEBUG ("Group destroyed: %s", 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 DEBUG ("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 DEBUG ("Contact %s (%d) removed from group %s",
154 empathy_contact_get_id (contact),
155 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 (!tp_strdiff (group, empathy_tp_group_get_name (l->data))) {
180 static TpContactListType
181 tp_contact_list_get_type (EmpathyTpContactList *list,
182 EmpathyTpGroup *group)
186 name = empathy_tp_group_get_name (group);
187 if (!tp_strdiff (name, "subscribe")) {
188 return TP_CONTACT_LIST_TYPE_SUBSCRIBE;
189 } else if (!tp_strdiff (name, "publish")) {
190 return TP_CONTACT_LIST_TYPE_PUBLISH;
193 return TP_CONTACT_LIST_TYPE_UNKNOWN;
197 tp_contact_list_add_member (EmpathyTpContactList *list,
198 EmpathyContact *contact,
199 EmpathyContact *actor,
201 const gchar *message)
203 EmpathyTpContactListPriv *priv = GET_PRIV (list);
206 /* Add to the list and emit signal */
207 priv->members = g_list_prepend (priv->members, g_object_ref (contact));
208 g_signal_emit_by_name (list, "members-changed",
209 contact, actor, reason, message,
212 /* This contact is now member, implicitly accept pending. */
213 if (g_list_find (priv->pendings, contact)) {
214 empathy_tp_group_add_member (priv->publish, contact, "");
217 /* Update groups of the contact */
218 for (l = priv->groups; l; l = l->next) {
219 if (empathy_tp_group_is_member (l->data, contact)) {
220 tp_contact_list_group_member_added_cb (l->data, contact,
228 tp_contact_list_added_cb (EmpathyTpGroup *group,
229 EmpathyContact *contact,
230 EmpathyContact *actor,
232 const gchar *message,
233 EmpathyTpContactList *list)
235 EmpathyTpContactListPriv *priv = GET_PRIV (list);
236 TpContactListType list_type;
238 list_type = tp_contact_list_get_type (list, group);
239 DEBUG ("Contact %s (%d) added to list type %d",
240 empathy_contact_get_id (contact),
241 empathy_contact_get_handle (contact),
244 /* We now get the presence of that contact, add it to members */
245 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
246 !g_list_find (priv->members, contact)) {
247 tp_contact_list_add_member (list, contact, actor, reason, message);
250 /* We now send our presence to that contact, remove it from pendings */
251 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
252 g_list_find (priv->pendings, contact)) {
253 g_signal_emit_by_name (list, "pendings-changed",
254 contact, actor, reason, message,
256 priv->pendings = g_list_remove (priv->pendings, contact);
257 g_object_unref (contact);
262 tp_contact_list_removed_cb (EmpathyTpGroup *group,
263 EmpathyContact *contact,
264 EmpathyContact *actor,
266 const gchar *message,
267 EmpathyTpContactList *list)
269 EmpathyTpContactListPriv *priv = GET_PRIV (list);
270 TpContactListType list_type;
272 list_type = tp_contact_list_get_type (list, group);
273 DEBUG ("Contact %s (%d) removed from list type %d",
274 empathy_contact_get_id (contact),
275 empathy_contact_get_handle (contact),
278 /* This contact refuses to send us his presence, remove from members. */
279 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
280 g_list_find (priv->members, contact)) {
281 g_signal_emit_by_name (list, "members-changed",
282 contact, actor, reason, message,
284 priv->members = g_list_remove (priv->members, contact);
285 g_object_unref (contact);
288 /* We refuse to send our presence to that contact, remove from pendings */
289 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
290 g_list_find (priv->pendings, contact)) {
291 g_signal_emit_by_name (list, "pendings-changed",
292 contact, actor, reason, message,
294 priv->pendings = g_list_remove (priv->pendings, contact);
295 g_object_unref (contact);
300 tp_contact_list_pending_cb (EmpathyTpGroup *group,
301 EmpathyContact *contact,
302 EmpathyContact *actor,
304 const gchar *message,
305 EmpathyTpContactList *list)
307 EmpathyTpContactListPriv *priv = GET_PRIV (list);
308 TpContactListType list_type;
310 list_type = tp_contact_list_get_type (list, group);
311 DEBUG ("Contact %s (%d) pending in list type %d",
312 empathy_contact_get_id (contact),
313 empathy_contact_get_handle (contact),
316 /* We want this contact in our contact list but we don't get its
317 * presence yet. Add to members anyway. */
318 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
319 !g_list_find (priv->members, contact)) {
320 tp_contact_list_add_member (list, contact, actor, reason, message);
323 /* This contact wants our presence, auto accept if he is member,
324 * otherwise he is pending. */
325 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
326 !g_list_find (priv->pendings, contact)) {
327 if (g_list_find (priv->members, contact)) {
328 empathy_tp_group_add_member (priv->publish, contact, "");
330 priv->pendings = g_list_prepend (priv->pendings,
331 g_object_ref (contact));
332 g_signal_emit_by_name (list, "pendings-changed",
333 contact, actor, reason, message,
340 tp_contact_list_invalidated_cb (TpConnection *connection,
344 EmpathyTpContactList *list)
346 EmpathyTpContactListPriv *priv = GET_PRIV (list);
349 DEBUG ("Connection invalidated");
351 /* Remove all contacts */
352 for (l = priv->members; l; l = l->next) {
353 g_signal_emit_by_name (list, "members-changed", l->data,
356 g_object_unref (l->data);
358 for (l = priv->pendings; l; l = l->next) {
359 g_signal_emit_by_name (list, "pendings-changed", l->data,
362 g_object_unref (l->data);
364 g_list_free (priv->members);
365 g_list_free (priv->pendings);
366 priv->members = NULL;
367 priv->pendings = NULL;
369 /* Tell the world to not use us anymore */
370 g_signal_emit (list, signals[DESTROY], 0);
374 tp_contact_list_group_list_free (GList **groups)
376 g_list_foreach (*groups, (GFunc) g_free, NULL);
377 g_list_free (*groups);
378 g_slice_free (GList*, groups);
382 tp_contact_list_add_channel (EmpathyTpContactList *list,
383 const gchar *object_path,
384 const gchar *channel_type,
385 TpHandleType handle_type,
388 EmpathyTpContactListPriv *priv = GET_PRIV (list);
390 EmpathyTpGroup *group;
391 const gchar *group_name;
394 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) != 0 ||
395 handle_type != TP_HANDLE_TYPE_GROUP) {
399 channel = tp_channel_new (priv->connection,
400 object_path, channel_type,
401 handle_type, handle, NULL);
403 group = empathy_tp_group_new (channel);
404 empathy_run_until_ready (group);
405 g_object_unref (channel);
407 /* Check if already exists */
408 group_name = empathy_tp_group_get_name (group);
409 if (tp_contact_list_find_group (list, group_name)) {
410 g_object_unref (group);
415 DEBUG ("New server-side group: %s", group_name);
416 priv->groups = g_list_prepend (priv->groups, group);
417 g_signal_connect (group, "member-added",
418 G_CALLBACK (tp_contact_list_group_member_added_cb),
420 g_signal_connect (group, "member-removed",
421 G_CALLBACK (tp_contact_list_group_member_removed_cb),
423 g_signal_connect (group, "destroy",
424 G_CALLBACK (tp_contact_list_group_destroy_cb),
427 /* Get initial members */
428 contacts = empathy_tp_group_get_members (group);
429 for (l = contacts; l; l = l->next) {
430 tp_contact_list_group_member_added_cb (group, l->data,
433 g_object_unref (l->data);
435 g_list_free (contacts);
439 tp_contact_list_new_channel_cb (TpConnection *proxy,
440 const gchar *object_path,
441 const gchar *channel_type,
444 gboolean suppress_handler,
448 EmpathyTpContactListPriv *priv = GET_PRIV (list);
450 if (!suppress_handler && priv->ready) {
451 tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
452 object_path, channel_type,
453 handle_type, handle);
458 tp_contact_list_list_channels_cb (TpConnection *connection,
459 const GPtrArray *channels,
464 EmpathyTpContactListPriv *priv = GET_PRIV (list);
468 DEBUG ("Error: %s", error->message);
472 for (i = 0; i < channels->len; i++) {
473 GValueArray *chan_struct;
474 const gchar *object_path;
475 const gchar *channel_type;
476 TpHandleType handle_type;
479 chan_struct = g_ptr_array_index (channels, i);
480 object_path = g_value_get_boxed (g_value_array_get_nth (chan_struct, 0));
481 channel_type = g_value_get_string (g_value_array_get_nth (chan_struct, 1));
482 handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2));
483 handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3));
485 tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
486 object_path, channel_type,
487 handle_type, handle);
494 tp_contact_list_request_channel_cb (TpConnection *connection,
495 const gchar *object_path,
498 GObject *weak_object)
500 EmpathyTpContactList *list = EMPATHY_TP_CONTACT_LIST (weak_object);
501 EmpathyTpContactListPriv *priv = GET_PRIV (list);
502 EmpathyTpGroup *group;
504 TpContactListType list_type;
508 DEBUG ("Error: %s", error->message);
512 channel = tp_channel_new (connection, object_path,
513 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
515 GPOINTER_TO_UINT (user_data),
517 group = empathy_tp_group_new (channel);
518 empathy_run_until_ready (group);
520 list_type = tp_contact_list_get_type (list, group);
521 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && !priv->publish) {
522 DEBUG ("Got publish list");
523 priv->publish = group;
525 /* Publish is the list of contacts to who we send our
526 * presence. Makes no sense to be in remote-pending */
527 g_signal_connect (group, "local-pending",
528 G_CALLBACK (tp_contact_list_pending_cb),
531 contacts = empathy_tp_group_get_local_pendings (group);
532 for (l = contacts; l; l = l->next) {
533 EmpathyPendingInfo *info = l->data;
534 tp_contact_list_pending_cb (group,
540 empathy_pending_info_free (info);
542 g_list_free (contacts);
544 else if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && !priv->subscribe) {
545 DEBUG ("Got subscribe list");
546 priv->subscribe = group;
548 /* Subscribe is the list of contacts from who we
549 * receive presence. Makes no sense to be in
551 g_signal_connect (group, "remote-pending",
552 G_CALLBACK (tp_contact_list_pending_cb),
555 contacts = empathy_tp_group_get_remote_pendings (group);
556 for (l = contacts; l; l = l->next) {
557 tp_contact_list_pending_cb (group,
561 g_object_unref (l->data);
563 g_list_free (contacts);
565 DEBUG ("Type of contact list channel unknown or aleady "
566 "have that list: %s",
567 empathy_tp_group_get_name (group));
568 g_object_unref (group);
572 /* For all list types when need to get members */
573 g_signal_connect (group, "member-added",
574 G_CALLBACK (tp_contact_list_added_cb),
576 g_signal_connect (group, "member-removed",
577 G_CALLBACK (tp_contact_list_removed_cb),
580 contacts = empathy_tp_group_get_members (group);
581 for (l = contacts; l; l = l->next) {
582 tp_contact_list_added_cb (group,
586 g_object_unref (l->data);
588 g_list_free (contacts);
592 tp_contact_list_request_handle_cb (TpConnection *connection,
593 const GArray *handles,
601 DEBUG ("Error: %s", error->message);
605 handle = g_array_index (handles, guint, 0);
606 tp_cli_connection_call_request_channel (connection, -1,
607 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
611 tp_contact_list_request_channel_cb,
612 GUINT_TO_POINTER (handle), NULL,
617 tp_contact_list_request_list (EmpathyTpContactList *list,
620 EmpathyTpContactListPriv *priv = GET_PRIV (list);
621 const gchar *names[] = {type, NULL};
623 tp_cli_connection_call_request_handles (priv->connection,
627 tp_contact_list_request_handle_cb,
633 tp_contact_list_finalize (GObject *object)
635 EmpathyTpContactListPriv *priv;
636 EmpathyTpContactList *list;
638 list = EMPATHY_TP_CONTACT_LIST (object);
639 priv = GET_PRIV (list);
641 DEBUG ("finalize: %p", object);
643 if (priv->subscribe) {
644 g_object_unref (priv->subscribe);
647 g_object_unref (priv->publish);
650 g_object_unref (priv->account);
652 if (priv->connection) {
653 g_signal_handlers_disconnect_by_func (priv->connection,
654 tp_contact_list_invalidated_cb,
656 g_object_unref (priv->connection);
659 g_hash_table_destroy (priv->contacts_groups);
660 g_list_foreach (priv->groups, (GFunc) g_object_unref, NULL);
661 g_list_free (priv->groups);
662 g_list_foreach (priv->members, (GFunc) g_object_unref, NULL);
663 g_list_free (priv->members);
664 g_list_foreach (priv->pendings, (GFunc) g_object_unref, NULL);
665 g_list_free (priv->pendings);
667 G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object);
671 tp_contact_list_connection_ready (TpConnection *connection,
675 EmpathyTpContactListPriv *priv = GET_PRIV (list);
678 tp_contact_list_invalidated_cb (connection,
682 EMPATHY_TP_CONTACT_LIST (list));
686 g_signal_connect (priv->connection, "invalidated",
687 G_CALLBACK (tp_contact_list_invalidated_cb),
690 tp_contact_list_request_list (list, "publish");
691 tp_contact_list_request_list (list, "subscribe");
693 tp_cli_connection_call_list_channels (priv->connection, -1,
694 tp_contact_list_list_channels_cb,
698 tp_cli_connection_connect_to_new_channel (priv->connection,
699 tp_contact_list_new_channel_cb,
705 tp_contact_list_constructed (GObject *list)
708 EmpathyTpContactListPriv *priv = GET_PRIV (list);
712 const gchar *protocol_name;
714 /* Get the connection. status==0 means CONNECTED */
715 mc = empathy_mission_control_dup_singleton ();
716 status = mission_control_get_connection_status (mc, priv->account, NULL);
717 g_return_if_fail (status == 0);
718 priv->connection = mission_control_get_tpconnection (mc, priv->account, NULL);
719 g_return_if_fail (priv->connection != NULL);
722 tp_connection_call_when_ready (priv->connection,
723 tp_contact_list_connection_ready,
726 /* Check for protocols that does not support contact groups. We can
727 * put all contacts into a special group in that case.
728 * FIXME: Default group should be an information in the profile */
729 profile = mc_account_get_profile (priv->account);
730 protocol_name = mc_profile_get_protocol_name (profile);
731 if (strcmp (protocol_name, "local-xmpp") == 0) {
732 priv->protocol_group = _("People nearby");
734 g_object_unref (profile);
738 tp_contact_list_get_property (GObject *object,
743 EmpathyTpContactListPriv *priv = GET_PRIV (object);
747 g_value_set_object (value, priv->account);
750 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
756 tp_contact_list_set_property (GObject *object,
761 EmpathyTpContactListPriv *priv = GET_PRIV (object);
765 priv->account = g_object_ref (g_value_get_object (value));
768 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
774 empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass)
776 GObjectClass *object_class = G_OBJECT_CLASS (klass);
778 object_class->finalize = tp_contact_list_finalize;
779 object_class->constructed = tp_contact_list_constructed;
780 object_class->get_property = tp_contact_list_get_property;
781 object_class->set_property = tp_contact_list_set_property;
783 g_object_class_install_property (object_class,
785 g_param_spec_object ("account",
787 "The account associated with the contact list",
790 G_PARAM_CONSTRUCT_ONLY));
793 g_signal_new ("destroy",
794 G_TYPE_FROM_CLASS (klass),
798 g_cclosure_marshal_VOID__VOID,
802 g_type_class_add_private (object_class, sizeof (EmpathyTpContactListPriv));
806 empathy_tp_contact_list_init (EmpathyTpContactList *list)
808 EmpathyTpContactListPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (list,
809 EMPATHY_TYPE_TP_CONTACT_LIST, EmpathyTpContactListPriv);
812 priv->contacts_groups = g_hash_table_new_full (g_direct_hash,
814 (GDestroyNotify) g_object_unref,
815 (GDestroyNotify) tp_contact_list_group_list_free);
818 EmpathyTpContactList *
819 empathy_tp_contact_list_new (McAccount *account)
821 return g_object_new (EMPATHY_TYPE_TP_CONTACT_LIST,
827 empathy_tp_contact_list_get_account (EmpathyTpContactList *list)
829 EmpathyTpContactListPriv *priv;
831 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
833 priv = GET_PRIV (list);
835 return priv->account;
839 tp_contact_list_add (EmpathyContactList *list,
840 EmpathyContact *contact,
841 const gchar *message)
843 EmpathyTpContactListPriv *priv = GET_PRIV (list);
845 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
847 if (priv->subscribe) {
848 empathy_tp_group_add_member (priv->subscribe, contact, message);
851 if (priv->publish && g_list_find (priv->pendings, contact)) {
852 empathy_tp_group_add_member (priv->publish, contact, message);
857 tp_contact_list_remove (EmpathyContactList *list,
858 EmpathyContact *contact,
859 const gchar *message)
861 EmpathyTpContactListPriv *priv = GET_PRIV (list);
863 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
865 if (priv->subscribe) {
866 empathy_tp_group_remove_member (priv->subscribe, contact, message);
869 empathy_tp_group_remove_member (priv->publish, contact, message);
874 tp_contact_list_get_members (EmpathyContactList *list)
876 EmpathyTpContactListPriv *priv = GET_PRIV (list);
878 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
880 g_list_foreach (priv->members, (GFunc) g_object_ref, NULL);
881 return g_list_copy (priv->members);
885 tp_contact_list_get_pendings (EmpathyContactList *list)
887 EmpathyTpContactListPriv *priv = GET_PRIV (list);
889 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
891 g_list_foreach (priv->pendings, (GFunc) g_object_ref, NULL);
892 return g_list_copy (priv->pendings);
896 tp_contact_list_get_all_groups (EmpathyContactList *list)
898 EmpathyTpContactListPriv *priv = GET_PRIV (list);
899 GList *groups = NULL, *l;
901 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
903 if (priv->protocol_group) {
904 groups = g_list_prepend (groups, g_strdup (priv->protocol_group));
907 for (l = priv->groups; l; l = l->next) {
910 name = empathy_tp_group_get_name (l->data);
911 groups = g_list_prepend (groups, g_strdup (name));
918 tp_contact_list_get_groups (EmpathyContactList *list,
919 EmpathyContact *contact)
921 EmpathyTpContactListPriv *priv = GET_PRIV (list);
923 GList *ret = NULL, *l;
925 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
927 if (priv->protocol_group) {
928 ret = g_list_prepend (ret, g_strdup (priv->protocol_group));
931 groups = g_hash_table_lookup (priv->contacts_groups, contact);
936 for (l = *groups; l; l = l->next) {
937 ret = g_list_prepend (ret, g_strdup (l->data));
944 static EmpathyTpGroup *
945 tp_contact_list_get_group (EmpathyTpContactList *list,
948 EmpathyTpContactListPriv *priv = GET_PRIV (list);
949 EmpathyTpGroup *tp_group;
953 const char *names[2] = {group, NULL};
954 GError *error = NULL;
956 tp_group = tp_contact_list_find_group (list, group);
961 DEBUG ("creating new group: %s", group);
963 if (!tp_cli_connection_run_request_handles (priv->connection, -1,
964 TP_HANDLE_TYPE_GROUP,
968 DEBUG ("Failed to RequestHandles: %s",
969 error ? error->message : "No error given");
970 g_clear_error (&error);
973 handle = g_array_index (handles, guint, 0);
974 g_array_free (handles, TRUE);
976 if (!tp_cli_connection_run_request_channel (priv->connection, -1,
977 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
978 TP_HANDLE_TYPE_GROUP,
983 DEBUG ("Failed to RequestChannel: %s",
984 error ? error->message : "No error given");
985 g_clear_error (&error);
989 tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
991 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
992 TP_HANDLE_TYPE_GROUP, handle);
994 g_free (object_path);
996 return tp_contact_list_find_group (list, group);
1000 tp_contact_list_add_to_group (EmpathyContactList *list,
1001 EmpathyContact *contact,
1004 EmpathyTpGroup *tp_group;
1006 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
1008 tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
1012 empathy_tp_group_add_member (tp_group, contact, "");
1017 tp_contact_list_remove_from_group (EmpathyContactList *list,
1018 EmpathyContact *contact,
1021 EmpathyTpGroup *tp_group;
1023 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
1025 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
1029 empathy_tp_group_remove_member (tp_group, contact, "");
1034 tp_contact_list_rename_group (EmpathyContactList *list,
1035 const gchar *old_group,
1036 const gchar *new_group)
1038 EmpathyTpGroup *tp_group;
1041 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
1043 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
1049 DEBUG ("rename group %s to %s", old_group, new_group);
1051 /* Remove all members from the old group */
1052 members = empathy_tp_group_get_members (tp_group);
1053 empathy_tp_group_remove_members (tp_group, members, "");
1054 empathy_tp_group_close (tp_group);
1056 /* Add all members to the new group */
1057 tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
1059 empathy_tp_group_add_members (tp_group, members, "");
1061 g_list_foreach (members, (GFunc) g_object_unref, NULL);
1062 g_list_free (members);
1066 tp_contact_list_remove_group (EmpathyContactList *list,
1069 EmpathyTpGroup *tp_group;
1072 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
1074 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
1081 DEBUG ("remove group %s", group);
1083 /* Remove all members of the group */
1084 members = empathy_tp_group_get_members (tp_group);
1085 empathy_tp_group_remove_members (tp_group, members, "");
1086 empathy_tp_group_close (tp_group);
1088 g_list_foreach (members, (GFunc) g_object_unref, NULL);
1089 g_list_free (members);
1093 tp_contact_list_iface_init (EmpathyContactListIface *iface)
1095 iface->add = tp_contact_list_add;
1096 iface->remove = tp_contact_list_remove;
1097 iface->get_members = tp_contact_list_get_members;
1098 iface->get_pendings = tp_contact_list_get_pendings;
1099 iface->get_all_groups = tp_contact_list_get_all_groups;
1100 iface->get_groups = tp_contact_list_get_groups;
1101 iface->add_to_group = tp_contact_list_add_to_group;
1102 iface->remove_from_group = tp_contact_list_remove_from_group;
1103 iface->rename_group = tp_contact_list_rename_group;
1104 iface->remove_group = tp_contact_list_remove_group;
1108 empathy_tp_contact_list_can_add (EmpathyTpContactList *list)
1110 EmpathyTpContactListPriv *priv;
1111 TpChannelGroupFlags flags;
1113 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), FALSE);
1115 priv = GET_PRIV (list);
1117 if (priv->subscribe == NULL)
1120 flags = empathy_tp_group_get_flags (priv->subscribe);
1121 return (flags & TP_CHANNEL_GROUP_FLAG_CAN_ADD) != 0;