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-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),
157 *groups = g_list_delete_link (*groups, l);
158 g_signal_emit_by_name (list, "groups-changed", contact,
164 static EmpathyTpGroup *
165 tp_contact_list_find_group (EmpathyTpContactList *list,
168 EmpathyTpContactListPriv *priv = GET_PRIV (list);
171 for (l = priv->groups; l; l = l->next) {
172 if (!tp_strdiff (group, empathy_tp_group_get_name (l->data))) {
179 static TpContactListType
180 tp_contact_list_get_type (EmpathyTpContactList *list,
181 EmpathyTpGroup *group)
185 name = empathy_tp_group_get_name (group);
186 if (!tp_strdiff (name, "subscribe")) {
187 return TP_CONTACT_LIST_TYPE_SUBSCRIBE;
188 } else if (!tp_strdiff (name, "publish")) {
189 return TP_CONTACT_LIST_TYPE_PUBLISH;
192 return TP_CONTACT_LIST_TYPE_UNKNOWN;
196 tp_contact_list_add_member (EmpathyTpContactList *list,
197 EmpathyContact *contact,
198 EmpathyContact *actor,
200 const gchar *message)
202 EmpathyTpContactListPriv *priv = GET_PRIV (list);
205 /* Add to the list and emit signal */
206 priv->members = g_list_prepend (priv->members, g_object_ref (contact));
207 g_signal_emit_by_name (list, "members-changed",
208 contact, actor, reason, message,
211 /* This contact is now member, implicitly accept pending. */
212 if (g_list_find (priv->pendings, contact)) {
213 empathy_tp_group_add_member (priv->publish, contact, "");
216 /* Update groups of the contact */
217 for (l = priv->groups; l; l = l->next) {
218 if (empathy_tp_group_is_member (l->data, contact)) {
219 tp_contact_list_group_member_added_cb (l->data, contact,
227 tp_contact_list_added_cb (EmpathyTpGroup *group,
228 EmpathyContact *contact,
229 EmpathyContact *actor,
231 const gchar *message,
232 EmpathyTpContactList *list)
234 EmpathyTpContactListPriv *priv = GET_PRIV (list);
235 TpContactListType list_type;
237 list_type = tp_contact_list_get_type (list, group);
238 DEBUG ("Contact %s (%d) added to list type %d",
239 empathy_contact_get_id (contact),
240 empathy_contact_get_handle (contact),
243 /* We now get the presence of that contact, add it to members */
244 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
245 !g_list_find (priv->members, contact)) {
246 tp_contact_list_add_member (list, contact, actor, reason, message);
249 /* We now send our presence to that contact, remove it from pendings */
250 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
251 g_list_find (priv->pendings, contact)) {
252 g_signal_emit_by_name (list, "pendings-changed",
253 contact, actor, reason, message,
255 priv->pendings = g_list_remove (priv->pendings, contact);
256 g_object_unref (contact);
261 tp_contact_list_removed_cb (EmpathyTpGroup *group,
262 EmpathyContact *contact,
263 EmpathyContact *actor,
265 const gchar *message,
266 EmpathyTpContactList *list)
268 EmpathyTpContactListPriv *priv = GET_PRIV (list);
269 TpContactListType list_type;
271 list_type = tp_contact_list_get_type (list, group);
272 DEBUG ("Contact %s (%d) removed from list type %d",
273 empathy_contact_get_id (contact),
274 empathy_contact_get_handle (contact),
277 /* This contact refuses to send us his presence, remove from members. */
278 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
279 g_list_find (priv->members, contact)) {
280 g_signal_emit_by_name (list, "members-changed",
281 contact, actor, reason, message,
283 priv->members = g_list_remove (priv->members, contact);
284 g_object_unref (contact);
287 /* We refuse to send our presence to that contact, remove from pendings */
288 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
289 g_list_find (priv->pendings, contact)) {
290 g_signal_emit_by_name (list, "pendings-changed",
291 contact, actor, reason, message,
293 priv->pendings = g_list_remove (priv->pendings, contact);
294 g_object_unref (contact);
299 tp_contact_list_pending_cb (EmpathyTpGroup *group,
300 EmpathyContact *contact,
301 EmpathyContact *actor,
303 const gchar *message,
304 EmpathyTpContactList *list)
306 EmpathyTpContactListPriv *priv = GET_PRIV (list);
307 TpContactListType list_type;
309 list_type = tp_contact_list_get_type (list, group);
310 DEBUG ("Contact %s (%d) pending in list type %d",
311 empathy_contact_get_id (contact),
312 empathy_contact_get_handle (contact),
315 /* We want this contact in our contact list but we don't get its
316 * presence yet. Add to members anyway. */
317 if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
318 !g_list_find (priv->members, contact)) {
319 tp_contact_list_add_member (list, contact, actor, reason, message);
322 /* This contact wants our presence, auto accept if he is member,
323 * otherwise he is pending. */
324 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
325 !g_list_find (priv->pendings, contact)) {
326 if (g_list_find (priv->members, contact)) {
327 empathy_tp_group_add_member (priv->publish, contact, "");
329 priv->pendings = g_list_prepend (priv->pendings,
330 g_object_ref (contact));
331 g_signal_emit_by_name (list, "pendings-changed",
332 contact, actor, reason, message,
339 tp_contact_list_invalidated_cb (TpConnection *connection,
343 EmpathyTpContactList *list)
345 EmpathyTpContactListPriv *priv = GET_PRIV (list);
348 DEBUG ("Connection invalidated");
350 /* Remove all contacts */
351 for (l = priv->members; l; l = l->next) {
352 g_signal_emit_by_name (list, "members-changed", l->data,
355 g_object_unref (l->data);
357 for (l = priv->pendings; l; l = l->next) {
358 g_signal_emit_by_name (list, "pendings-changed", l->data,
361 g_object_unref (l->data);
363 g_list_free (priv->members);
364 g_list_free (priv->pendings);
365 priv->members = NULL;
366 priv->pendings = NULL;
368 /* Tell the world to not use us anymore */
369 g_signal_emit (list, signals[DESTROY], 0);
373 tp_contact_list_group_list_free (GList **groups)
375 g_list_foreach (*groups, (GFunc) g_free, NULL);
376 g_list_free (*groups);
377 g_slice_free (GList*, groups);
381 tp_contact_list_add_channel (EmpathyTpContactList *list,
382 const gchar *object_path,
383 const gchar *channel_type,
384 TpHandleType handle_type,
387 EmpathyTpContactListPriv *priv = GET_PRIV (list);
388 EmpathyTpGroup *group;
391 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) != 0 ||
392 (handle_type != TP_HANDLE_TYPE_LIST &&
393 handle_type != TP_HANDLE_TYPE_GROUP)) {
397 channel = tp_channel_new (priv->connection,
398 object_path, channel_type,
399 handle_type, handle, NULL);
401 group = empathy_tp_group_new (channel);
402 empathy_run_until_ready (group);
403 g_object_unref (channel);
405 if (handle_type == TP_HANDLE_TYPE_LIST) {
406 TpContactListType list_type;
409 list_type = tp_contact_list_get_type (list, group);
410 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && !priv->publish) {
411 priv->publish = g_object_ref (group);
413 /* Publish is the list of contacts to who we send our
414 * presence. Makes no sense to be in remote-pending */
415 g_signal_connect (group, "local-pending",
416 G_CALLBACK (tp_contact_list_pending_cb),
419 contacts = empathy_tp_group_get_local_pendings (group);
420 for (l = contacts; l; l = l->next) {
421 EmpathyPendingInfo *info = l->data;
423 tp_contact_list_pending_cb (group,
429 empathy_pending_info_free (info);
431 g_list_free (contacts);
433 else if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && !priv->subscribe) {
434 priv->subscribe = g_object_ref (group);
436 /* Subscribe is the list of contacts from who we
437 * receive presence. Makes no sense to be in
439 g_signal_connect (group, "remote-pending",
440 G_CALLBACK (tp_contact_list_pending_cb),
443 contacts = empathy_tp_group_get_remote_pendings (group);
444 for (l = contacts; l; l = l->next) {
445 tp_contact_list_pending_cb (group,
449 g_object_unref (l->data);
451 g_list_free (contacts);
453 DEBUG ("Type of contact list channel unknown or aleady "
454 "have that list: %s",
455 empathy_tp_group_get_name (group));
458 DEBUG ("New contact list channel of type: %d", list_type);
460 g_signal_connect (group, "member-added",
461 G_CALLBACK (tp_contact_list_added_cb),
463 g_signal_connect (group, "member-removed",
464 G_CALLBACK (tp_contact_list_removed_cb),
467 contacts = empathy_tp_group_get_members (group);
468 for (l = contacts; l; l = l->next) {
469 tp_contact_list_added_cb (group,
473 g_object_unref (l->data);
475 g_list_free (contacts);
477 else if (handle_type == TP_HANDLE_TYPE_GROUP) {
478 const gchar *group_name;
481 /* Check if already exists */
482 group_name = empathy_tp_group_get_name (group);
483 if (tp_contact_list_find_group (list, group_name)) {
487 DEBUG ("New server-side group channel: %s", group_name);
489 priv->groups = g_list_prepend (priv->groups, g_object_ref (group));
491 g_signal_connect (group, "member-added",
492 G_CALLBACK (tp_contact_list_group_member_added_cb),
494 g_signal_connect (group, "member-removed",
495 G_CALLBACK (tp_contact_list_group_member_removed_cb),
497 g_signal_connect (group, "destroy",
498 G_CALLBACK (tp_contact_list_group_destroy_cb),
501 contacts = empathy_tp_group_get_members (group);
502 for (l = contacts; l; l = l->next) {
503 tp_contact_list_group_member_added_cb (group, l->data,
506 g_object_unref (l->data);
508 g_list_free (contacts);
510 DEBUG ("Unknown handle type (%d) for contact list channel",
515 g_object_unref (group);
519 tp_contact_list_new_channel_cb (TpConnection *proxy,
520 const gchar *object_path,
521 const gchar *channel_type,
524 gboolean suppress_handler,
528 EmpathyTpContactListPriv *priv = GET_PRIV (list);
530 if (!suppress_handler && priv->ready) {
531 tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
532 object_path, channel_type,
533 handle_type, handle);
538 tp_contact_list_list_channels_cb (TpConnection *connection,
539 const GPtrArray *channels,
544 EmpathyTpContactListPriv *priv = GET_PRIV (list);
548 DEBUG ("Failed to get list of open channels: %s",
549 error ? error->message : "No error given");
553 for (i = 0; i < channels->len; i++) {
554 GValueArray *chan_struct;
555 const gchar *object_path;
556 const gchar *channel_type;
557 TpHandleType handle_type;
560 chan_struct = g_ptr_array_index (channels, i);
561 object_path = g_value_get_boxed (g_value_array_get_nth (chan_struct, 0));
562 channel_type = g_value_get_string (g_value_array_get_nth (chan_struct, 1));
563 handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2));
564 handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3));
566 tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
567 object_path, channel_type,
568 handle_type, handle);
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 DEBUG ("finalize: %p", object);
585 if (priv->subscribe) {
586 g_object_unref (priv->subscribe);
589 g_object_unref (priv->publish);
592 g_object_unref (priv->account);
594 if (priv->connection) {
595 g_signal_handlers_disconnect_by_func (priv->connection,
596 tp_contact_list_invalidated_cb,
598 g_object_unref (priv->connection);
601 g_hash_table_destroy (priv->contacts_groups);
602 g_list_foreach (priv->groups, (GFunc) g_object_unref, NULL);
603 g_list_free (priv->groups);
604 g_list_foreach (priv->members, (GFunc) g_object_unref, NULL);
605 g_list_free (priv->members);
606 g_list_foreach (priv->pendings, (GFunc) g_object_unref, NULL);
607 g_list_free (priv->pendings);
609 G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object);
613 tp_contact_list_ready_cb (EmpathyTpContactList *list)
615 EmpathyTpContactListPriv *priv = GET_PRIV (list);
617 tp_cli_connection_call_list_channels (priv->connection, -1,
618 tp_contact_list_list_channels_cb,
622 tp_cli_connection_connect_to_new_channel (priv->connection,
623 tp_contact_list_new_channel_cb,
625 G_OBJECT (list), NULL);
629 tp_contact_list_constructed (GObject *list)
632 EmpathyTpContactListPriv *priv = GET_PRIV (list);
637 const gchar *protocol_name;
639 /* Get the connection. status==0 means CONNECTED */
640 mc = empathy_mission_control_new ();
641 status = mission_control_get_connection_status (mc, priv->account, NULL);
642 g_return_if_fail (status == 0);
643 priv->connection = mission_control_get_tpconnection (mc, priv->account, NULL);
644 g_return_if_fail (priv->connection != NULL);
647 g_signal_connect (priv->connection, "invalidated",
648 G_CALLBACK (tp_contact_list_invalidated_cb),
650 g_object_get (priv->connection, "connection-ready", &ready, NULL);
652 tp_contact_list_ready_cb (EMPATHY_TP_CONTACT_LIST (list));
654 g_signal_connect_swapped (priv->connection, "notify::connection-ready",
655 G_CALLBACK (tp_contact_list_ready_cb),
659 /* Check for protocols that does not support contact groups. We can
660 * put all contacts into a special group in that case.
661 * FIXME: Default group should be an information in the profile */
662 profile = mc_account_get_profile (priv->account);
663 protocol_name = mc_profile_get_protocol_name (profile);
664 if (strcmp (protocol_name, "local-xmpp") == 0) {
665 priv->protocol_group = _("People nearby");
667 g_object_unref (profile);
671 tp_contact_list_get_property (GObject *object,
676 EmpathyTpContactListPriv *priv = GET_PRIV (object);
680 g_value_set_object (value, priv->account);
683 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
689 tp_contact_list_set_property (GObject *object,
694 EmpathyTpContactListPriv *priv = GET_PRIV (object);
698 priv->account = g_object_ref (g_value_get_object (value));
701 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
707 empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass)
709 GObjectClass *object_class = G_OBJECT_CLASS (klass);
711 object_class->finalize = tp_contact_list_finalize;
712 object_class->constructed = tp_contact_list_constructed;
713 object_class->get_property = tp_contact_list_get_property;
714 object_class->set_property = tp_contact_list_set_property;
716 g_object_class_install_property (object_class,
718 g_param_spec_object ("account",
720 "The account associated with the contact list",
723 G_PARAM_CONSTRUCT_ONLY));
726 g_signal_new ("destroy",
727 G_TYPE_FROM_CLASS (klass),
731 g_cclosure_marshal_VOID__VOID,
735 g_type_class_add_private (object_class, sizeof (EmpathyTpContactListPriv));
739 empathy_tp_contact_list_init (EmpathyTpContactList *list)
741 EmpathyTpContactListPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (list,
742 EMPATHY_TYPE_TP_CONTACT_LIST, EmpathyTpContactListPriv);
745 priv->contacts_groups = g_hash_table_new_full (g_direct_hash,
747 (GDestroyNotify) g_object_unref,
748 (GDestroyNotify) tp_contact_list_group_list_free);
751 EmpathyTpContactList *
752 empathy_tp_contact_list_new (McAccount *account)
754 return g_object_new (EMPATHY_TYPE_TP_CONTACT_LIST,
760 empathy_tp_contact_list_get_account (EmpathyTpContactList *list)
762 EmpathyTpContactListPriv *priv;
764 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
766 priv = GET_PRIV (list);
768 return priv->account;
772 tp_contact_list_add (EmpathyContactList *list,
773 EmpathyContact *contact,
774 const gchar *message)
776 EmpathyTpContactListPriv *priv = GET_PRIV (list);
778 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
780 empathy_tp_group_add_member (priv->subscribe, contact, message);
781 if (g_list_find (priv->pendings, contact)) {
782 empathy_tp_group_add_member (priv->publish, contact, message);
787 tp_contact_list_remove (EmpathyContactList *list,
788 EmpathyContact *contact,
789 const gchar *message)
791 EmpathyTpContactListPriv *priv = GET_PRIV (list);
793 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
795 empathy_tp_group_remove_member (priv->subscribe, contact, message);
796 empathy_tp_group_remove_member (priv->publish, contact, message);
800 tp_contact_list_get_members (EmpathyContactList *list)
802 EmpathyTpContactListPriv *priv = GET_PRIV (list);
804 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
806 g_list_foreach (priv->members, (GFunc) g_object_ref, NULL);
807 return g_list_copy (priv->members);
811 tp_contact_list_get_pendings (EmpathyContactList *list)
813 EmpathyTpContactListPriv *priv = GET_PRIV (list);
815 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
817 g_list_foreach (priv->pendings, (GFunc) g_object_ref, NULL);
818 return g_list_copy (priv->pendings);
822 tp_contact_list_get_all_groups (EmpathyContactList *list)
824 EmpathyTpContactListPriv *priv = GET_PRIV (list);
825 GList *groups = NULL, *l;
827 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
829 if (priv->protocol_group) {
830 groups = g_list_prepend (groups, g_strdup (priv->protocol_group));
833 for (l = priv->groups; l; l = l->next) {
836 name = empathy_tp_group_get_name (l->data);
837 groups = g_list_prepend (groups, g_strdup (name));
844 tp_contact_list_get_groups (EmpathyContactList *list,
845 EmpathyContact *contact)
847 EmpathyTpContactListPriv *priv = GET_PRIV (list);
849 GList *ret = NULL, *l;
851 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
853 if (priv->protocol_group) {
854 ret = g_list_prepend (ret, g_strdup (priv->protocol_group));
857 groups = g_hash_table_lookup (priv->contacts_groups, contact);
862 for (l = *groups; l; l = l->next) {
863 ret = g_list_prepend (ret, g_strdup (l->data));
870 static EmpathyTpGroup *
871 tp_contact_list_get_group (EmpathyTpContactList *list,
874 EmpathyTpContactListPriv *priv = GET_PRIV (list);
875 EmpathyTpGroup *tp_group;
879 const char *names[2] = {group, NULL};
880 GError *error = NULL;
882 tp_group = tp_contact_list_find_group (list, group);
887 DEBUG ("creating new group: %s", group);
889 if (!tp_cli_connection_run_request_handles (priv->connection, -1,
890 TP_HANDLE_TYPE_GROUP,
894 DEBUG ("Failed to RequestHandles: %s",
895 error ? error->message : "No error given");
896 g_clear_error (&error);
899 handle = g_array_index (handles, guint, 0);
900 g_array_free (handles, TRUE);
902 if (!tp_cli_connection_run_request_channel (priv->connection, -1,
903 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
904 TP_HANDLE_TYPE_GROUP,
909 DEBUG ("Failed to RequestChannel: %s",
910 error ? error->message : "No error given");
911 g_clear_error (&error);
915 tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
917 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
918 TP_HANDLE_TYPE_GROUP, handle);
920 g_free (object_path);
922 return tp_contact_list_find_group (list, group);
926 tp_contact_list_add_to_group (EmpathyContactList *list,
927 EmpathyContact *contact,
930 EmpathyTpGroup *tp_group;
932 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
934 tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
937 empathy_tp_group_add_member (tp_group, contact, "");
941 tp_contact_list_remove_from_group (EmpathyContactList *list,
942 EmpathyContact *contact,
945 EmpathyTpGroup *tp_group;
947 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
949 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
953 empathy_tp_group_remove_member (tp_group, contact, "");
958 tp_contact_list_rename_group (EmpathyContactList *list,
959 const gchar *old_group,
960 const gchar *new_group)
962 EmpathyTpGroup *tp_group;
965 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
967 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
973 DEBUG ("rename group %s to %s", old_group, new_group);
975 /* Remove all members from the old group */
976 members = empathy_tp_group_get_members (tp_group);
977 empathy_tp_group_remove_members (tp_group, members, "");
978 empathy_tp_group_close (tp_group);
980 /* Add all members to the new group */
981 tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
983 empathy_tp_group_add_members (tp_group, members, "");
985 g_list_foreach (members, (GFunc) g_object_unref, NULL);
986 g_list_free (members);
990 tp_contact_list_remove_group (EmpathyContactList *list,
993 EmpathyTpGroup *tp_group;
996 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
998 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
1005 DEBUG ("remove group %s", group);
1007 /* Remove all members of the group */
1008 members = empathy_tp_group_get_members (tp_group);
1009 empathy_tp_group_remove_members (tp_group, members, "");
1010 empathy_tp_group_close (tp_group);
1012 g_list_foreach (members, (GFunc) g_object_unref, NULL);
1013 g_list_free (members);
1017 tp_contact_list_iface_init (EmpathyContactListIface *iface)
1019 iface->add = tp_contact_list_add;
1020 iface->remove = tp_contact_list_remove;
1021 iface->get_members = tp_contact_list_get_members;
1022 iface->get_pendings = tp_contact_list_get_pendings;
1023 iface->get_all_groups = tp_contact_list_get_all_groups;
1024 iface->get_groups = tp_contact_list_get_groups;
1025 iface->add_to_group = tp_contact_list_add_to_group;
1026 iface->remove_from_group = tp_contact_list_remove_from_group;
1027 iface->rename_group = tp_contact_list_rename_group;
1028 iface->remove_group = tp_contact_list_remove_group;