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 <libtelepathy/tp-conn.h>
29 #include <libtelepathy/tp-chan.h>
30 #include <libtelepathy/tp-chan-type-contact-list-gen.h>
31 #include <telepathy-glib/util.h>
32 #include <telepathy-glib/dbus.h>
34 #include "empathy-tp-contact-list.h"
35 #include "empathy-contact-list.h"
36 #include "empathy-tp-group.h"
37 #include "empathy-debug.h"
38 #include "empathy-utils.h"
40 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
41 EMPATHY_TYPE_TP_CONTACT_LIST, EmpathyTpContactListPriv))
43 #define DEBUG_DOMAIN "TpContactList"
45 struct _EmpathyTpContactListPriv {
49 const gchar *protocol_group;
51 EmpathyTpGroup *publish;
52 EmpathyTpGroup *subscribe;
57 GHashTable *contacts_groups;
61 TP_CONTACT_LIST_TYPE_PUBLISH,
62 TP_CONTACT_LIST_TYPE_SUBSCRIBE,
63 TP_CONTACT_LIST_TYPE_UNKNOWN
66 static void empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass);
67 static void empathy_tp_contact_list_init (EmpathyTpContactList *list);
68 static void tp_contact_list_iface_init (EmpathyContactListIface *iface);
75 static guint signals[LAST_SIGNAL];
77 G_DEFINE_TYPE_WITH_CODE (EmpathyTpContactList, empathy_tp_contact_list, G_TYPE_OBJECT,
78 G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST,
79 tp_contact_list_iface_init));
82 tp_contact_list_group_destroy_cb (EmpathyTpGroup *group,
83 EmpathyTpContactList *list)
85 EmpathyTpContactListPriv *priv = GET_PRIV (list);
87 empathy_debug (DEBUG_DOMAIN, "Group destroyed: %s",
88 empathy_tp_group_get_name (group));
90 priv->groups = g_list_remove (priv->groups, group);
91 g_object_unref (group);
95 tp_contact_list_group_member_added_cb (EmpathyTpGroup *group,
96 EmpathyContact *contact,
97 EmpathyContact *actor,
100 EmpathyTpContactList *list)
102 EmpathyTpContactListPriv *priv = GET_PRIV (list);
103 const gchar *group_name;
106 if (!g_list_find (priv->members, contact)) {
110 groups = g_hash_table_lookup (priv->contacts_groups, contact);
112 groups = g_slice_new0 (GList*);
113 g_hash_table_insert (priv->contacts_groups,
114 g_object_ref (contact),
118 group_name = empathy_tp_group_get_name (group);
119 if (!g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp)) {
120 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) added to group %s",
121 empathy_contact_get_id (contact),
122 empathy_contact_get_handle (contact),
124 *groups = g_list_prepend (*groups, g_strdup (group_name));
125 g_signal_emit_by_name (list, "groups-changed", contact,
132 tp_contact_list_group_member_removed_cb (EmpathyTpGroup *group,
133 EmpathyContact *contact,
134 EmpathyContact *actor,
136 const gchar *message,
137 EmpathyTpContactList *list)
139 EmpathyTpContactListPriv *priv = GET_PRIV (list);
140 const gchar *group_name;
143 if (!g_list_find (priv->members, contact)) {
147 groups = g_hash_table_lookup (priv->contacts_groups, contact);
152 group_name = empathy_tp_group_get_name (group);
153 if ((l = g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp))) {
154 empathy_debug (DEBUG_DOMAIN, "Contact %s (%d) removed from group %s",
155 empathy_contact_get_id (contact),
156 empathy_contact_get_handle (contact),
158 *groups = g_list_delete_link (*groups, l);
159 g_signal_emit_by_name (list, "groups-changed", contact,
165 static EmpathyTpGroup *
166 tp_contact_list_find_group (EmpathyTpContactList *list,
169 EmpathyTpContactListPriv *priv = GET_PRIV (list);
172 for (l = priv->groups; l; l = l->next) {
173 if (!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 empathy_debug (DEBUG_DOMAIN, "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 empathy_debug (DEBUG_DOMAIN, "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 empathy_debug (DEBUG_DOMAIN, "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_group_ready_cb (EmpathyTpGroup *group,
342 EmpathyTpContactList *list)
344 EmpathyTpContactListPriv *priv = GET_PRIV (list);
348 tp_chan = empathy_tp_group_get_channel (group);
349 handle_type = tp_chan->handle_type;
351 if (handle_type == TP_HANDLE_TYPE_LIST) {
352 TpContactListType list_type;
355 list_type = tp_contact_list_get_type (list, group);
356 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && !priv->publish) {
357 priv->publish = g_object_ref (group);
359 /* Publish is the list of contacts to who we send our
360 * presence. Makes no sense to be in remote-pending */
361 g_signal_connect (group, "local-pending",
362 G_CALLBACK (tp_contact_list_pending_cb),
365 contacts = empathy_tp_group_get_local_pendings (group);
366 for (l = contacts; l; l = l->next) {
367 EmpathyPendingInfo *info = l->data;
369 tp_contact_list_pending_cb (group,
375 empathy_pending_info_free (info);
377 g_list_free (contacts);
379 else if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && !priv->subscribe) {
380 priv->subscribe = g_object_ref (group);
382 /* Subscribe is the list of contacts from who we
383 * receive presence. Makes no sense to be in
385 g_signal_connect (group, "remote-pending",
386 G_CALLBACK (tp_contact_list_pending_cb),
389 contacts = empathy_tp_group_get_remote_pendings (group);
390 for (l = contacts; l; l = l->next) {
391 tp_contact_list_pending_cb (group,
395 g_object_unref (l->data);
397 g_list_free (contacts);
399 empathy_debug (DEBUG_DOMAIN,
400 "Type of contact list channel unknown "
401 "or aleady have that list: %s",
402 empathy_tp_group_get_name (group));
405 empathy_debug (DEBUG_DOMAIN,
406 "New contact list channel of type: %d",
409 g_signal_connect (group, "member-added",
410 G_CALLBACK (tp_contact_list_added_cb),
412 g_signal_connect (group, "member-removed",
413 G_CALLBACK (tp_contact_list_removed_cb),
416 contacts = empathy_tp_group_get_members (group);
417 for (l = contacts; l; l = l->next) {
418 tp_contact_list_added_cb (group,
422 g_object_unref (l->data);
424 g_list_free (contacts);
426 else if (handle_type == TP_HANDLE_TYPE_GROUP) {
427 const gchar *group_name;
430 /* Check if already exists */
431 group_name = empathy_tp_group_get_name (group);
432 if (tp_contact_list_find_group (list, group_name)) {
436 empathy_debug (DEBUG_DOMAIN, "New server-side group channel: %s",
439 priv->groups = g_list_prepend (priv->groups, g_object_ref (group));
441 g_signal_connect (group, "member-added",
442 G_CALLBACK (tp_contact_list_group_member_added_cb),
444 g_signal_connect (group, "member-removed",
445 G_CALLBACK (tp_contact_list_group_member_removed_cb),
447 g_signal_connect (group, "destroy",
448 G_CALLBACK (tp_contact_list_group_destroy_cb),
451 contacts = empathy_tp_group_get_members (group);
452 for (l = contacts; l; l = l->next) {
453 tp_contact_list_group_member_added_cb (group, l->data,
456 g_object_unref (l->data);
458 g_list_free (contacts);
460 empathy_debug (DEBUG_DOMAIN,
461 "Unknown handle type (%d) for contact list channel",
466 g_object_unref (group);
467 g_object_unref (list);
471 tp_contact_list_newchannel_cb (DBusGProxy *proxy,
472 const gchar *object_path,
473 const gchar *channel_type,
474 TpHandleType handle_type,
475 guint channel_handle,
476 gboolean suppress_handler,
477 EmpathyTpContactList *list)
479 EmpathyTpContactListPriv *priv = GET_PRIV (list);
480 EmpathyTpGroup *group;
482 const gchar *bus_name;
484 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) != 0 ||
486 (handle_type != TP_HANDLE_TYPE_LIST &&
487 handle_type != TP_HANDLE_TYPE_GROUP)) {
491 bus_name = dbus_g_proxy_get_bus_name (DBUS_G_PROXY (priv->tp_conn));
492 new_chan = tp_chan_new (tp_get_bus (),
498 g_return_if_fail (TELEPATHY_IS_CHAN (new_chan));
500 group = empathy_tp_group_new (priv->account, new_chan);
501 g_object_unref (new_chan);
503 /* We give a ref of group and list to the callback */
504 if (empathy_tp_group_is_ready (group)) {
505 tp_contact_list_group_ready_cb (group, NULL, g_object_ref (list));
507 g_signal_connect (group, "notify::ready",
508 G_CALLBACK (tp_contact_list_group_ready_cb),
509 g_object_ref (list));
514 tp_contact_list_destroy_cb (TpConn *tp_conn,
515 EmpathyTpContactList *list)
517 EmpathyTpContactListPriv *priv = GET_PRIV (list);
520 empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed");
522 /* DBus proxie should NOT be used anymore */
523 g_object_unref (priv->tp_conn);
524 priv->tp_conn = NULL;
526 /* Remove all contacts */
527 for (l = priv->members; l; l = l->next) {
528 g_signal_emit_by_name (list, "members-changed", l->data,
531 g_object_unref (l->data);
533 for (l = priv->pendings; l; l = l->next) {
534 g_signal_emit_by_name (list, "pendings-changed", l->data,
537 g_object_unref (l->data);
539 g_list_free (priv->members);
540 g_list_free (priv->pendings);
541 priv->members = NULL;
542 priv->pendings = NULL;
544 /* Tell the world to not use us anymore */
545 g_signal_emit (list, signals[DESTROY], 0);
549 tp_contact_list_disconnect (EmpathyTpContactList *list)
551 EmpathyTpContactListPriv *priv = GET_PRIV (list);
554 g_signal_handlers_disconnect_by_func (priv->tp_conn,
555 tp_contact_list_destroy_cb,
557 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->tp_conn), "NewChannel",
558 G_CALLBACK (tp_contact_list_newchannel_cb),
564 tp_contact_list_status_changed_cb (MissionControl *mc,
565 TpConnectionStatus status,
567 TpConnectionStatusReason reason,
568 const gchar *unique_name,
569 EmpathyTpContactList *list)
571 EmpathyTpContactListPriv *priv = GET_PRIV (list);
574 account = mc_account_lookup (unique_name);
575 if (status != TP_CONNECTION_STATUS_CONNECTED &&
576 empathy_account_equal (account, priv->account)) {
577 /* We are disconnected */
578 tp_contact_list_disconnect (list);
579 tp_contact_list_destroy_cb (priv->tp_conn, list);
582 g_object_unref (account);
586 tp_contact_list_group_list_free (GList **groups)
588 g_list_foreach (*groups, (GFunc) g_free, NULL);
589 g_list_free (*groups);
590 g_slice_free (GList*, groups);
594 tp_contact_list_finalize (GObject *object)
596 EmpathyTpContactListPriv *priv;
597 EmpathyTpContactList *list;
599 list = EMPATHY_TP_CONTACT_LIST (object);
600 priv = GET_PRIV (list);
602 empathy_debug (DEBUG_DOMAIN, "finalize: %p", object);
604 tp_contact_list_disconnect (list);
607 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
608 "AccountStatusChanged",
609 G_CALLBACK (tp_contact_list_status_changed_cb),
611 g_object_unref (priv->mc);
614 if (priv->subscribe) {
615 g_object_unref (priv->subscribe);
618 g_object_unref (priv->publish);
621 g_object_unref (priv->account);
624 g_object_unref (priv->tp_conn);
627 g_hash_table_destroy (priv->contacts_groups);
628 g_list_foreach (priv->groups, (GFunc) g_object_unref, NULL);
629 g_list_free (priv->groups);
630 g_list_foreach (priv->members, (GFunc) g_object_unref, NULL);
631 g_list_free (priv->members);
632 g_list_foreach (priv->pendings, (GFunc) g_object_unref, NULL);
633 g_list_free (priv->pendings);
635 G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object);
639 empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass)
641 GObjectClass *object_class = G_OBJECT_CLASS (klass);
643 object_class->finalize = tp_contact_list_finalize;
646 g_signal_new ("destroy",
647 G_TYPE_FROM_CLASS (klass),
651 g_cclosure_marshal_VOID__VOID,
655 g_type_class_add_private (object_class, sizeof (EmpathyTpContactListPriv));
659 empathy_tp_contact_list_init (EmpathyTpContactList *list)
664 tp_contact_list_setup (EmpathyTpContactList *list)
666 EmpathyTpContactListPriv *priv = GET_PRIV (list);
669 GError *error = NULL;
671 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
673 /* Get existing channels */
674 if (!tp_conn_list_channels (DBUS_G_PROXY (priv->tp_conn),
677 empathy_debug (DEBUG_DOMAIN,
678 "Failed to get list of open channels: %s",
679 error ? error->message : "No error given");
680 g_clear_error (&error);
684 for (i = 0; i < channels->len; i++) {
685 GValueArray *chan_struct;
686 const gchar *object_path;
687 const gchar *chan_iface;
688 TpHandleType handle_type;
691 chan_struct = g_ptr_array_index (channels, i);
692 object_path = g_value_get_boxed (g_value_array_get_nth (chan_struct, 0));
693 chan_iface = g_value_get_string (g_value_array_get_nth (chan_struct, 1));
694 handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2));
695 handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3));
697 tp_contact_list_newchannel_cb (DBUS_G_PROXY (priv->tp_conn),
698 object_path, chan_iface,
703 g_value_array_free (chan_struct);
705 g_ptr_array_free (channels, TRUE);
708 EmpathyTpContactList *
709 empathy_tp_contact_list_new (McAccount *account)
711 EmpathyTpContactListPriv *priv;
712 EmpathyTpContactList *list;
714 TpConn *tp_conn = NULL;
716 const gchar *protocol_name;
718 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
720 mc = empathy_mission_control_new ();
722 /* status==0 means CONNECTED */
723 if (mission_control_get_connection_status (mc, account, NULL) == 0) {
724 tp_conn = mission_control_get_connection (mc, account, NULL);
727 /* The account is not connected, nothing to do. */
732 list = g_object_new (EMPATHY_TYPE_TP_CONTACT_LIST, NULL);
733 priv = GET_PRIV (list);
735 priv->tp_conn = tp_conn;
736 priv->account = g_object_ref (account);
738 priv->contacts_groups = g_hash_table_new_full (g_direct_hash,
740 (GDestroyNotify) g_object_unref,
741 (GDestroyNotify) tp_contact_list_group_list_free);
743 /* Check for protocols that does not support contact groups. We can
744 * put all contacts into a special group in that case.
745 * FIXME: Default group should be an information in the profile */
746 profile = mc_account_get_profile (account);
747 protocol_name = mc_profile_get_protocol_name (profile);
748 if (strcmp (protocol_name, "local-xmpp") == 0) {
749 priv->protocol_group = _("People nearby");
751 g_object_unref (profile);
753 /* Connect signals */
754 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
755 "AccountStatusChanged",
756 G_CALLBACK (tp_contact_list_status_changed_cb),
758 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->tp_conn), "NewChannel",
759 G_CALLBACK (tp_contact_list_newchannel_cb),
761 g_signal_connect (priv->tp_conn, "destroy",
762 G_CALLBACK (tp_contact_list_destroy_cb),
765 tp_contact_list_setup (list);
771 empathy_tp_contact_list_get_account (EmpathyTpContactList *list)
773 EmpathyTpContactListPriv *priv;
775 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
777 priv = GET_PRIV (list);
779 return priv->account;
783 tp_contact_list_add (EmpathyContactList *list,
784 EmpathyContact *contact,
785 const gchar *message)
787 EmpathyTpContactListPriv *priv = GET_PRIV (list);
789 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
791 empathy_tp_group_add_member (priv->subscribe, contact, message);
792 if (g_list_find (priv->pendings, contact)) {
793 empathy_tp_group_add_member (priv->publish, contact, message);
798 tp_contact_list_remove (EmpathyContactList *list,
799 EmpathyContact *contact,
800 const gchar *message)
802 EmpathyTpContactListPriv *priv = GET_PRIV (list);
804 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
806 empathy_tp_group_remove_member (priv->subscribe, contact, message);
807 empathy_tp_group_remove_member (priv->publish, contact, message);
811 tp_contact_list_get_members (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->members, (GFunc) g_object_ref, NULL);
818 return g_list_copy (priv->members);
822 tp_contact_list_get_pendings (EmpathyContactList *list)
824 EmpathyTpContactListPriv *priv = GET_PRIV (list);
826 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
828 g_list_foreach (priv->pendings, (GFunc) g_object_ref, NULL);
829 return g_list_copy (priv->pendings);
833 tp_contact_list_get_all_groups (EmpathyContactList *list)
835 EmpathyTpContactListPriv *priv = GET_PRIV (list);
836 GList *groups = NULL, *l;
838 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
840 if (priv->protocol_group) {
841 groups = g_list_prepend (groups, g_strdup (priv->protocol_group));
844 for (l = priv->groups; l; l = l->next) {
847 name = empathy_tp_group_get_name (l->data);
848 groups = g_list_prepend (groups, g_strdup (name));
855 tp_contact_list_get_groups (EmpathyContactList *list,
856 EmpathyContact *contact)
858 EmpathyTpContactListPriv *priv = GET_PRIV (list);
860 GList *ret = NULL, *l;
862 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
864 if (priv->protocol_group) {
865 ret = g_list_prepend (ret, g_strdup (priv->protocol_group));
868 groups = g_hash_table_lookup (priv->contacts_groups, contact);
873 for (l = *groups; l; l = l->next) {
874 ret = g_list_prepend (ret, g_strdup (l->data));
881 static EmpathyTpGroup *
882 tp_contact_list_get_group (EmpathyTpContactList *list,
885 EmpathyTpContactListPriv *priv = GET_PRIV (list);
886 EmpathyTpGroup *tp_group;
890 const char *names[2] = {group, NULL};
891 GError *error = NULL;
893 tp_group = tp_contact_list_find_group (list, group);
898 empathy_debug (DEBUG_DOMAIN, "creating new group: %s", group);
900 if (!tp_conn_request_handles (DBUS_G_PROXY (priv->tp_conn),
901 TP_HANDLE_TYPE_GROUP,
905 empathy_debug (DEBUG_DOMAIN,
906 "Failed to RequestHandles: %s",
907 error ? error->message : "No error given");
908 g_clear_error (&error);
911 handle = g_array_index (handles, guint, 0);
912 g_array_free (handles, TRUE);
914 if (!tp_conn_request_channel (DBUS_G_PROXY (priv->tp_conn),
915 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
916 TP_HANDLE_TYPE_GROUP,
921 empathy_debug (DEBUG_DOMAIN,
922 "Failed to RequestChannel: %s",
923 error ? error->message : "No error given");
924 g_clear_error (&error);
928 tp_contact_list_newchannel_cb (DBUS_G_PROXY (priv->tp_conn),
930 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
931 TP_HANDLE_TYPE_GROUP,
934 g_free (object_path);
936 return tp_contact_list_find_group (list, group);
940 tp_contact_list_add_to_group (EmpathyContactList *list,
941 EmpathyContact *contact,
944 EmpathyTpGroup *tp_group;
946 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
948 tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
951 empathy_tp_group_add_member (tp_group, contact, "");
955 tp_contact_list_remove_from_group (EmpathyContactList *list,
956 EmpathyContact *contact,
959 EmpathyTpGroup *tp_group;
961 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
963 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
967 empathy_tp_group_remove_member (tp_group, contact, "");
972 tp_contact_list_rename_group (EmpathyContactList *list,
973 const gchar *old_group,
974 const gchar *new_group)
976 EmpathyTpGroup *tp_group;
979 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
981 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
987 empathy_debug (DEBUG_DOMAIN, "rename group %s to %s", old_group, new_group);
989 /* Remove all members from the old group */
990 members = empathy_tp_group_get_members (tp_group);
991 empathy_tp_group_remove_members (tp_group, members, "");
992 empathy_tp_group_close (tp_group);
994 /* Add all members to the new group */
995 tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
997 empathy_tp_group_add_members (tp_group, members, "");
999 g_list_foreach (members, (GFunc) g_object_unref, NULL);
1000 g_list_free (members);
1004 tp_contact_list_remove_group (EmpathyContactList *list,
1007 EmpathyTpGroup *tp_group;
1010 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
1012 tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
1019 empathy_debug (DEBUG_DOMAIN, "remove group %s", group);
1021 /* Remove all members of the group */
1022 members = empathy_tp_group_get_members (tp_group);
1023 empathy_tp_group_remove_members (tp_group, members, "");
1024 empathy_tp_group_close (tp_group);
1026 g_list_foreach (members, (GFunc) g_object_unref, NULL);
1027 g_list_free (members);
1031 tp_contact_list_iface_init (EmpathyContactListIface *iface)
1033 iface->add = tp_contact_list_add;
1034 iface->remove = tp_contact_list_remove;
1035 iface->get_members = tp_contact_list_get_members;
1036 iface->get_pendings = tp_contact_list_get_pendings;
1037 iface->get_all_groups = tp_contact_list_get_all_groups;
1038 iface->get_groups = tp_contact_list_get_groups;
1039 iface->add_to_group = tp_contact_list_add_to_group;
1040 iface->remove_from_group = tp_contact_list_remove_from_group;
1041 iface->rename_group = tp_contact_list_rename_group;
1042 iface->remove_group = tp_contact_list_remove_group;