telepathy: implement some sipe_backend_buddy_XXX() calls
[siplcs.git] / src / telepathy / telepathy-buddy.c
blobbac90e1444681f36f0ec433431f1cfc7aeee4a4e
1 /**
2 * @file telepathy-buddy.c
4 * pidgin-sipe
6 * Copyright (C) 2012 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <glib-object.h>
24 #include <telepathy-glib/base-connection.h>
25 #include <telepathy-glib/base-contact-list.h>
26 #include <telepathy-glib/telepathy-glib.h>
28 #include "sipe-backend.h"
29 #include "sipe-common.h"
30 #include "sipe-core.h"
32 #include "telepathy-private.h"
34 struct telepathy_buddy {
35 const gchar *uri; /* borrowed from contact_list->buddies key */
36 GHashTable *groups; /* keys are borrowed from contact_list->groups */
37 TpHandle handle;
40 struct telepathy_buddy_entry {
41 const gchar *uri; /* borrowed from telepathy_buddy->uri */
42 const gchar *group; /* borrowed from contact_list->groups key */
43 gchar *alias;
46 G_BEGIN_DECLS
48 * Contact List class - data structures
50 typedef struct _SipeContactListClass {
51 TpBaseContactListClass parent_class;
52 } SipeContactListClass;
54 typedef struct _SipeContactList {
55 TpBaseContactList parent;
57 TpBaseConnection *connection;
58 TpHandleRepoIface *contact_repo;
59 TpHandleSet *contacts;
61 GHashTable *buddies;
62 GHashTable *buddy_handles;
63 GHashTable *groups;
65 gboolean initial_received;
66 } SipeContactList;
69 * Contact List class - type macros
71 static GType sipe_contact_list_get_type(void) G_GNUC_CONST;
72 #define SIPE_TYPE_CONTACT_LIST \
73 (sipe_contact_list_get_type())
74 #define SIPE_CONTACT_LIST(obj) \
75 (G_TYPE_CHECK_INSTANCE_CAST((obj), SIPE_TYPE_CONTACT_LIST, \
76 SipeContactList))
77 G_END_DECLS
80 * Contact List class - type definition
82 static void contact_group_list_iface_init(TpContactGroupListInterface *);
83 G_DEFINE_TYPE_WITH_CODE(SipeContactList,
84 sipe_contact_list,
85 TP_TYPE_BASE_CONTACT_LIST,
86 G_IMPLEMENT_INTERFACE (TP_TYPE_CONTACT_GROUP_LIST,
87 contact_group_list_iface_init);
92 * Contact List class - instance methods
94 static TpHandleSet *dup_contacts(TpBaseContactList *contact_list)
96 SipeContactList *self = SIPE_CONTACT_LIST(contact_list);
97 return(tp_handle_set_copy(self->contacts));
100 static void dup_states(SIPE_UNUSED_PARAMETER TpBaseContactList *contact_list,
101 SIPE_UNUSED_PARAMETER TpHandle contact,
102 TpSubscriptionState *subscribe,
103 TpSubscriptionState *publish,
104 gchar **publish_request)
106 /* @TODO */
107 SIPE_DEBUG_INFO_NOFORMAT("SipeContactList::dup_states - NOT IMPLEMENTED");
109 if (subscribe)
110 *subscribe = TP_SUBSCRIPTION_STATE_YES;
111 if (publish)
112 *publish = TP_SUBSCRIPTION_STATE_YES;
113 if (publish_request)
114 *publish_request = g_strdup("");
117 static void sipe_contact_list_constructed(GObject *object)
119 SipeContactList *self = SIPE_CONTACT_LIST(object);
120 void (*chain_up)(GObject *) = G_OBJECT_CLASS(sipe_contact_list_parent_class)->constructed;
122 if (chain_up)
123 chain_up(object);
125 g_object_get(self, "connection", &self->connection, NULL);
126 self->contact_repo = tp_base_connection_get_handles(self->connection,
127 TP_HANDLE_TYPE_CONTACT);
128 self->contacts = tp_handle_set_new(self->contact_repo);
131 static void sipe_contact_list_dispose(GObject *object)
133 SipeContactList *self = SIPE_CONTACT_LIST(object);
134 void (*chain_up)(GObject *) = G_OBJECT_CLASS(sipe_contact_list_parent_class)->dispose;
136 SIPE_DEBUG_INFO_NOFORMAT("SipeContactList::dispose");
138 tp_clear_pointer(&self->contacts, tp_handle_set_destroy);
139 tp_clear_object(&self->connection);
140 /* NOTE: the order is important due to borrowing of keys! */
141 tp_clear_pointer(&self->buddy_handles, g_hash_table_unref);
142 tp_clear_pointer(&self->buddies, g_hash_table_unref);
143 tp_clear_pointer(&self->groups, g_hash_table_unref);
145 if (chain_up)
146 chain_up(object);
150 * Contact List class - type implementation
152 static void sipe_contact_list_class_init(SipeContactListClass *klass)
154 GObjectClass *object_class = G_OBJECT_CLASS(klass);
155 TpBaseContactListClass *base_class = TP_BASE_CONTACT_LIST_CLASS(klass);
157 SIPE_DEBUG_INFO_NOFORMAT("SipeContactList::class_init");
159 object_class->constructed = sipe_contact_list_constructed;
160 object_class->dispose = sipe_contact_list_dispose;
162 base_class->dup_contacts = dup_contacts;
163 base_class->dup_states = dup_states;
166 static void buddy_free(gpointer data);
167 static void sipe_contact_list_init(SIPE_UNUSED_PARAMETER SipeContactList *self)
169 SIPE_DEBUG_INFO_NOFORMAT("SipeContactList::init");
171 self->buddies = g_hash_table_new_full(g_str_hash, g_str_equal,
172 g_free, buddy_free);
173 self->buddy_handles = g_hash_table_new(g_direct_hash, g_direct_equal);
174 self->groups = g_hash_table_new_full(g_str_hash, g_str_equal,
175 g_free, NULL);
177 self->initial_received = FALSE;
181 * Contact List class - interface implementation
183 * Contact groups
185 static GStrv dup_groups(TpBaseContactList *contact_list)
187 SipeContactList *self = SIPE_CONTACT_LIST(contact_list);
188 GPtrArray *groups = g_ptr_array_sized_new(
189 g_hash_table_size(self->groups) + 1);
190 GHashTableIter iter;
191 gpointer name;
193 SIPE_DEBUG_INFO_NOFORMAT("SipeContactList::dup_groups called");
195 g_hash_table_iter_init(&iter, self->groups);
196 while (g_hash_table_iter_next(&iter, &name, NULL))
197 g_ptr_array_add(groups, g_strdup(name));
198 g_ptr_array_add(groups, NULL);
200 return((GStrv) g_ptr_array_free(groups, FALSE));
203 static TpHandleSet *dup_group_members(TpBaseContactList *contact_list,
204 const gchar *group_name)
206 SipeContactList *self = SIPE_CONTACT_LIST(contact_list);
207 TpHandleSet *members = tp_handle_set_new(self->contact_repo);
208 GHashTableIter iter;
209 struct telepathy_buddy *buddy;
211 SIPE_DEBUG_INFO_NOFORMAT("SipeContactList::dup_group_members called");
213 g_hash_table_iter_init(&iter, self->buddies);
214 while (g_hash_table_iter_next(&iter, NULL, (gpointer) &buddy))
215 if (g_hash_table_lookup(buddy->groups, group_name))
216 tp_handle_set_add(members, buddy->handle);
218 return(members);
221 static GStrv dup_contact_groups(TpBaseContactList *contact_list,
222 TpHandle contact)
224 SipeContactList *self = SIPE_CONTACT_LIST(contact_list);
225 GPtrArray *groups = g_ptr_array_sized_new(
226 g_hash_table_size(self->groups) + 1);
227 struct telepathy_buddy *buddy = g_hash_table_lookup(self->buddy_handles,
228 GUINT_TO_POINTER(contact));
230 SIPE_DEBUG_INFO_NOFORMAT("SipeContactList::dup_contact_groups called");
232 if (buddy) {
233 GHashTableIter iter;
234 const gchar *group_name;
236 g_hash_table_iter_init(&iter, buddy->groups);
237 while (g_hash_table_iter_next(&iter,
238 (gpointer) &group_name,
239 NULL))
240 g_ptr_array_add(groups, g_strdup(group_name));
242 g_ptr_array_add(groups, NULL);
244 return((GStrv) g_ptr_array_free(groups, FALSE));
247 static void contact_group_list_iface_init(TpContactGroupListInterface *iface)
249 iface->dup_groups = dup_groups;
250 iface->dup_group_members = dup_group_members;
251 iface->dup_contact_groups = dup_contact_groups;
254 /* create new contact list object */
255 SipeContactList *sipe_telepathy_contact_list_new(TpBaseConnection *connection)
257 return(g_object_new(SIPE_TYPE_CONTACT_LIST,
258 "connection", connection,
259 NULL));
263 * Backend adaptor functions
265 sipe_backend_buddy sipe_backend_buddy_find(struct sipe_core_public *sipe_public,
266 const gchar *buddy_name,
267 const gchar *group_name)
269 struct sipe_backend_private *telepathy_private = sipe_public->backend_private;
270 struct telepathy_buddy *buddy = g_hash_table_lookup(telepathy_private->contact_list->buddies,
271 buddy_name);
272 if (!buddy)
273 return(NULL);
275 if (group_name) {
276 return(g_hash_table_lookup(buddy->groups, group_name));
277 } else {
278 /* just return the first entry */
279 GHashTableIter iter;
280 gpointer value;
281 g_hash_table_iter_init(&iter, buddy->groups);
282 g_hash_table_iter_next(&iter, NULL, &value);
283 return(value);
287 static GSList *buddy_add_all(struct telepathy_buddy *buddy, GSList *list)
289 GHashTableIter iter;
290 struct telepathy_buddy_entry *buddy_entry;
292 if (!buddy)
293 return(list);
295 g_hash_table_iter_init(&iter, buddy->groups);
296 while (g_hash_table_iter_next(&iter, NULL, (gpointer) &buddy_entry))
297 list = g_slist_prepend(list, buddy_entry);
299 return(list);
302 GSList *sipe_backend_buddy_find_all(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public,
303 const gchar *buddy_name,
304 const gchar *group_name)
306 GSList *result = NULL;
308 /* NOTE: group_name != NULL not implemented in purple either */
309 if (!group_name) {
310 struct sipe_backend_private *telepathy_private = sipe_public->backend_private;
311 GHashTable *buddies = telepathy_private->contact_list->buddies;
313 if (buddy_name) {
314 result = buddy_add_all(g_hash_table_lookup(buddies,
315 buddy_name),
316 result);
317 } else {
318 GHashTableIter biter;
319 struct telepathy_buddy *buddy;
321 g_hash_table_iter_init(&biter, telepathy_private->contact_list->buddies);
322 while (g_hash_table_iter_next(&biter, NULL, (gpointer) &buddy))
323 result = buddy_add_all(buddy, result);
327 return(result);
330 gchar *sipe_backend_buddy_get_name(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public,
331 const sipe_backend_buddy who)
333 return(g_strdup(((struct telepathy_buddy_entry *) who)->uri));
336 gchar *sipe_backend_buddy_get_alias(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public,
337 const sipe_backend_buddy who)
339 return(g_strdup(((struct telepathy_buddy_entry *) who)->alias));
342 gchar *sipe_backend_buddy_get_group_name(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public,
343 const sipe_backend_buddy who)
345 return(g_strdup(((struct telepathy_buddy_entry *) who)->group));
348 void sipe_backend_buddy_set_alias(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public,
349 const sipe_backend_buddy who,
350 const gchar *alias)
352 struct telepathy_buddy_entry *buddy_entry = who;
353 g_free(buddy_entry->alias);
354 buddy_entry->alias = g_strdup(alias);
356 /* @TODO: emit signal? */
359 void sipe_backend_buddy_list_processing_finish(struct sipe_core_public *sipe_public)
361 struct sipe_backend_private *telepathy_private = sipe_public->backend_private;
362 SipeContactList *contact_list = telepathy_private->contact_list;
364 if (!contact_list->initial_received) {
365 /* we can only call this once */
366 contact_list->initial_received = TRUE;
367 SIPE_DEBUG_INFO_NOFORMAT("sipe_backend_buddy_list_processing_finish called");
368 tp_base_contact_list_set_list_received(TP_BASE_CONTACT_LIST(contact_list));
372 static void buddy_free(gpointer data)
374 struct telepathy_buddy *buddy = data;
375 g_hash_table_destroy(buddy->groups);
376 g_free(buddy);
379 static void buddy_entry_free(gpointer data)
381 struct telepathy_buddy_entry *buddy_entry = data;
382 g_free(buddy_entry->alias);
383 g_free(buddy_entry);
386 sipe_backend_buddy sipe_backend_buddy_add(struct sipe_core_public *sipe_public,
387 const gchar *name,
388 const gchar *alias,
389 const gchar *group_name)
391 struct sipe_backend_private *telepathy_private = sipe_public->backend_private;
392 SipeContactList *contact_list = telepathy_private->contact_list;
393 const gchar *group = g_hash_table_lookup(contact_list->groups,
394 group_name);
395 struct telepathy_buddy *buddy = g_hash_table_lookup(contact_list->buddies,
396 name);
397 struct telepathy_buddy_entry *buddy_entry;
399 if (!group)
400 return(NULL);
402 if (!buddy) {
403 buddy = g_new0(struct telepathy_buddy, 1);
404 buddy->uri = g_strdup(name); /* reused as key */
405 buddy->groups = g_hash_table_new_full(g_str_hash, g_str_equal,
406 NULL, buddy_entry_free);
407 buddy->handle = tp_handle_ensure(contact_list->contact_repo,
408 buddy->uri, NULL, NULL);
409 tp_handle_set_add(contact_list->contacts, buddy->handle);
410 g_hash_table_insert(contact_list->buddies,
411 (gchar *) buddy->uri, /* owned by hash table */
412 buddy);
413 g_hash_table_insert(contact_list->buddy_handles,
414 GUINT_TO_POINTER(buddy->handle),
415 buddy);
418 buddy_entry = g_hash_table_lookup(buddy->groups, group);
419 if (!buddy_entry) {
420 buddy_entry = g_new0(struct telepathy_buddy_entry, 1);
421 buddy_entry->uri = buddy->uri;
422 buddy_entry->group = group;
423 buddy_entry->alias = g_strdup(alias);
424 g_hash_table_insert(buddy->groups,
425 (gchar *) group, /* key is borrowed */
426 buddy_entry);
429 if (contact_list->initial_received) {
430 /* @TODO: emit signal? */
433 return(buddy_entry);
436 void sipe_backend_buddy_remove(struct sipe_core_public *sipe_public,
437 const sipe_backend_buddy who)
439 struct sipe_backend_private *telepathy_private = sipe_public->backend_private;
440 SipeContactList *contact_list = telepathy_private->contact_list;
441 struct telepathy_buddy_entry *remove_entry = who;
442 struct telepathy_buddy *buddy = g_hash_table_lookup(contact_list->buddies,
443 remove_entry->uri);
445 if (buddy) {
446 struct telepathy_buddy_entry *buddy_entry = g_hash_table_lookup(buddy->groups,
447 remove_entry->group);
449 if (buddy_entry == remove_entry) {
450 /* match found -> remove this entry */
451 g_hash_table_remove(buddy->groups,
452 remove_entry->group);
454 if (g_hash_table_size(buddy->groups) == 0) {
455 /* removed from last group -> drop this buddy */
456 tp_handle_set_remove(contact_list->contacts,
457 buddy->handle);
458 g_hash_table_remove(contact_list->buddy_handles,
459 GUINT_TO_POINTER(buddy->handle));
460 g_hash_table_remove(contact_list->buddies,
461 remove_entry->uri);
465 if (contact_list->initial_received) {
466 /* @TODO: emit signal? */
472 gboolean sipe_backend_buddy_group_add(struct sipe_core_public *sipe_public,
473 const gchar *group_name)
475 struct sipe_backend_private *telepathy_private = sipe_public->backend_private;
476 SipeContactList *contact_list = telepathy_private->contact_list;
477 gchar *group = g_hash_table_lookup(contact_list->groups,
478 group_name);
480 if (!group) {
481 group = g_strdup(group_name);
482 g_hash_table_insert(contact_list->groups, group, group);
483 tp_base_contact_list_groups_created(TP_BASE_CONTACT_LIST(contact_list),
484 &group_name,
488 return(group != NULL);
493 Local Variables:
494 mode: c
495 c-file-style: "bsd"
496 indent-tabs-mode: t
497 tab-width: 8
498 End: