2 * @file telepathy-buddy.c
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
25 #include <glib-object.h>
26 #include <glib/gstdio.h>
27 #include <telepathy-glib/base-connection.h>
28 #include <telepathy-glib/base-contact-list.h>
29 #include <telepathy-glib/telepathy-glib.h>
31 #include "sipe-backend.h"
32 #include "sipe-common.h"
33 #include "sipe-core.h"
35 #include "telepathy-private.h"
37 #define SIPE_INFO_FIELD_MAX (SIPE_BUDDY_INFO_CUSTOM1_PHONE_DISPLAY + 1)
39 struct telepathy_buddy
{
40 const gchar
*uri
; /* borrowed from contact_list->buddies key */
41 GHashTable
*groups
; /* key: group name, value: buddy_entry */
42 /* keys are borrowed from contact_list->groups */
44 /* includes alias as stored on the server */
45 gchar
*info
[SIPE_INFO_FIELD_MAX
];
46 gchar
*hash
; /* photo hash */
50 struct telepathy_buddy_entry
{
51 struct telepathy_buddy
*buddy
; /* pointer to parent */
52 const gchar
*group
; /* borrowed from contact_list->groups key */
57 * Contact List class - data structures
59 typedef struct _SipeContactListClass
{
60 TpBaseContactListClass parent_class
;
61 } SipeContactListClass
;
63 typedef struct _SipeContactList
{
64 TpBaseContactList parent
;
66 TpBaseConnection
*connection
;
67 TpHandleRepoIface
*contact_repo
;
68 TpHandleSet
*contacts
;
70 GHashTable
*buddies
; /* key: SIP URI, value: buddy */
71 GHashTable
*buddy_handles
; /* key: TpHandle, value: buddy */
72 GHashTable
*groups
; /* key: group name, value: buddy */
74 gboolean initial_received
;
78 * Contact List class - type macros
80 static GType
sipe_contact_list_get_type(void) G_GNUC_CONST
;
81 #define SIPE_TYPE_CONTACT_LIST \
82 (sipe_contact_list_get_type())
83 #define SIPE_CONTACT_LIST(obj) \
84 (G_TYPE_CHECK_INSTANCE_CAST((obj), SIPE_TYPE_CONTACT_LIST, \
89 * Contact List class - type definition
91 static void contact_group_list_iface_init(TpContactGroupListInterface
*);
92 G_DEFINE_TYPE_WITH_CODE(SipeContactList
,
94 TP_TYPE_BASE_CONTACT_LIST
,
95 G_IMPLEMENT_INTERFACE (TP_TYPE_CONTACT_GROUP_LIST
,
96 contact_group_list_iface_init
);
101 * Contact List class - instance methods
103 static TpHandleSet
*dup_contacts(TpBaseContactList
*contact_list
)
105 SipeContactList
*self
= SIPE_CONTACT_LIST(contact_list
);
106 return(tp_handle_set_copy(self
->contacts
));
109 static void dup_states(SIPE_UNUSED_PARAMETER TpBaseContactList
*contact_list
,
110 SIPE_UNUSED_PARAMETER TpHandle contact
,
111 TpSubscriptionState
*subscribe
,
112 TpSubscriptionState
*publish
,
113 gchar
**publish_request
)
116 SIPE_DEBUG_INFO_NOFORMAT("SipeContactList::dup_states - NOT IMPLEMENTED");
119 *subscribe
= TP_SUBSCRIPTION_STATE_YES
;
121 *publish
= TP_SUBSCRIPTION_STATE_YES
;
123 *publish_request
= g_strdup("");
126 static void sipe_contact_list_constructed(GObject
*object
)
128 SipeContactList
*self
= SIPE_CONTACT_LIST(object
);
129 void (*chain_up
)(GObject
*) = G_OBJECT_CLASS(sipe_contact_list_parent_class
)->constructed
;
134 g_object_get(self
, "connection", &self
->connection
, NULL
);
135 self
->contact_repo
= tp_base_connection_get_handles(self
->connection
,
136 TP_HANDLE_TYPE_CONTACT
);
137 self
->contacts
= tp_handle_set_new(self
->contact_repo
);
140 static void sipe_contact_list_dispose(GObject
*object
)
142 SipeContactList
*self
= SIPE_CONTACT_LIST(object
);
143 void (*chain_up
)(GObject
*) = G_OBJECT_CLASS(sipe_contact_list_parent_class
)->dispose
;
145 SIPE_DEBUG_INFO_NOFORMAT("SipeContactList::dispose");
147 tp_clear_pointer(&self
->contacts
, tp_handle_set_destroy
);
148 tp_clear_object(&self
->connection
);
149 /* NOTE: the order is important due to borrowing of keys! */
150 tp_clear_pointer(&self
->buddy_handles
, g_hash_table_unref
);
151 tp_clear_pointer(&self
->buddies
, g_hash_table_unref
);
152 tp_clear_pointer(&self
->groups
, g_hash_table_unref
);
159 * Contact List class - type implementation
161 static void sipe_contact_list_class_init(SipeContactListClass
*klass
)
163 GObjectClass
*object_class
= G_OBJECT_CLASS(klass
);
164 TpBaseContactListClass
*base_class
= TP_BASE_CONTACT_LIST_CLASS(klass
);
166 SIPE_DEBUG_INFO_NOFORMAT("SipeContactList::class_init");
168 object_class
->constructed
= sipe_contact_list_constructed
;
169 object_class
->dispose
= sipe_contact_list_dispose
;
171 base_class
->dup_contacts
= dup_contacts
;
172 base_class
->dup_states
= dup_states
;
175 static void buddy_free(gpointer data
);
176 static void sipe_contact_list_init(SIPE_UNUSED_PARAMETER SipeContactList
*self
)
178 SIPE_DEBUG_INFO_NOFORMAT("SipeContactList::init");
180 self
->buddies
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
182 self
->buddy_handles
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
183 self
->groups
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
186 self
->initial_received
= FALSE
;
190 * Contact List class - interface implementation
194 static GStrv
dup_groups(TpBaseContactList
*contact_list
)
196 SipeContactList
*self
= SIPE_CONTACT_LIST(contact_list
);
197 GPtrArray
*groups
= g_ptr_array_sized_new(
198 g_hash_table_size(self
->groups
) + 1);
202 SIPE_DEBUG_INFO_NOFORMAT("SipeContactList::dup_groups called");
204 g_hash_table_iter_init(&iter
, self
->groups
);
205 while (g_hash_table_iter_next(&iter
, &name
, NULL
))
206 g_ptr_array_add(groups
, g_strdup(name
));
207 g_ptr_array_add(groups
, NULL
);
209 return((GStrv
) g_ptr_array_free(groups
, FALSE
));
212 static TpHandleSet
*dup_group_members(TpBaseContactList
*contact_list
,
213 const gchar
*group_name
)
215 SipeContactList
*self
= SIPE_CONTACT_LIST(contact_list
);
216 TpHandleSet
*members
= tp_handle_set_new(self
->contact_repo
);
218 struct telepathy_buddy
*buddy
;
220 SIPE_DEBUG_INFO_NOFORMAT("SipeContactList::dup_group_members called");
222 g_hash_table_iter_init(&iter
, self
->buddies
);
223 while (g_hash_table_iter_next(&iter
, NULL
, (gpointer
) &buddy
))
224 if (g_hash_table_lookup(buddy
->groups
, group_name
))
225 tp_handle_set_add(members
, buddy
->handle
);
230 static GStrv
dup_contact_groups(TpBaseContactList
*contact_list
,
233 SipeContactList
*self
= SIPE_CONTACT_LIST(contact_list
);
234 GPtrArray
*groups
= g_ptr_array_sized_new(
235 g_hash_table_size(self
->groups
) + 1);
236 struct telepathy_buddy
*buddy
= g_hash_table_lookup(self
->buddy_handles
,
237 GUINT_TO_POINTER(contact
));
239 SIPE_DEBUG_INFO_NOFORMAT("SipeContactList::dup_contact_groups called");
243 const gchar
*group_name
;
245 g_hash_table_iter_init(&iter
, buddy
->groups
);
246 while (g_hash_table_iter_next(&iter
,
247 (gpointer
) &group_name
,
249 g_ptr_array_add(groups
, g_strdup(group_name
));
251 g_ptr_array_add(groups
, NULL
);
253 return((GStrv
) g_ptr_array_free(groups
, FALSE
));
256 static void contact_group_list_iface_init(TpContactGroupListInterface
*iface
)
258 #define IMPLEMENT(x) iface->x = x
259 IMPLEMENT(dup_groups
);
260 IMPLEMENT(dup_group_members
);
261 IMPLEMENT(dup_contact_groups
);
265 /* create new contact list object */
266 SipeContactList
*sipe_telepathy_contact_list_new(TpBaseConnection
*connection
)
268 return(g_object_new(SIPE_TYPE_CONTACT_LIST
,
269 "connection", connection
,
273 /* get & set alias for a contact */
274 const gchar
*sipe_telepathy_buddy_get_alias(SipeContactList
*contact_list
,
277 struct telepathy_buddy
*buddy
= g_hash_table_lookup(contact_list
->buddy_handles
,
278 GUINT_TO_POINTER(contact
));
281 return(buddy
->info
[SIPE_BUDDY_INFO_DISPLAY_NAME
]);
284 static void update_alias(struct telepathy_buddy
*buddy
,
288 g_free(buddy
->info
[SIPE_BUDDY_INFO_DISPLAY_NAME
]);
289 buddy
->info
[SIPE_BUDDY_INFO_DISPLAY_NAME
] = g_strdup(alias
);
293 void sipe_telepathy_buddy_set_alias(SipeContactList
*contact_list
,
297 struct telepathy_buddy
*buddy
= g_hash_table_lookup(contact_list
->buddy_handles
,
298 GUINT_TO_POINTER(contact
));
299 update_alias(buddy
, alias
);
301 /* tell core about the alias change */
303 struct sipe_backend_private
*telepathy_private
= sipe_telepathy_connection_private(G_OBJECT(contact_list
->connection
));
304 sipe_core_group_set_alias(telepathy_private
->public,
310 /* get presence status for a contact */
311 guint
sipe_telepathy_buddy_get_presence(SipeContactList
*contact_list
,
312 const TpHandle contact
)
314 struct telepathy_buddy
*buddy
= g_hash_table_lookup(contact_list
->buddy_handles
,
315 GUINT_TO_POINTER(contact
));
317 return(SIPE_ACTIVITY_UNSET
);
318 return(buddy
->activity
);
321 static const gchar
*const sipe_to_vcard_field
[SIPE_INFO_FIELD_MAX
] = {
322 /* SIPE_BUDDY_INFO_DISPLAY_NAME */ "fn",
323 /* SIPE_BUDDY_INFO_JOB_TITLE */ "title",
324 /* SIPE_BUDDY_INFO_CITY */ NULL
,
325 /* SIPE_BUDDY_INFO_STATE */ NULL
,
326 /* SIPE_BUDDY_INFO_OFFICE */ NULL
,
327 /* SIPE_BUDDY_INFO_DEPARTMENT */ NULL
,
328 /* SIPE_BUDDY_INFO_COUNTRY */ NULL
,
329 /* SIPE_BUDDY_INFO_WORK_PHONE */ "tel",
330 /* SIPE_BUDDY_INFO_WORK_PHONE_DISPLAY */ NULL
,
331 /* SIPE_BUDDY_INFO_COMPANY */ "org",
332 /* SIPE_BUDDY_INFO_EMAIL */ "email",
333 /* SIPE_BUDDY_INFO_SITE */ NULL
,
334 /* SIPE_BUDDY_INFO_ZIPCODE */ NULL
,
335 /* SIPE_BUDDY_INFO_STREET */ NULL
,
336 /* SIPE_BUDDY_INFO_MOBILE_PHONE */ NULL
,
337 /* SIPE_BUDDY_INFO_MOBILE_PHONE_DISPLAY */ NULL
,
338 /* SIPE_BUDDY_INFO_HOME_PHONE */ NULL
,
339 /* SIPE_BUDDY_INFO_HOME_PHONE_DISPLAY */ NULL
,
340 /* SIPE_BUDDY_INFO_OTHER_PHONE */ NULL
,
341 /* SIPE_BUDDY_INFO_OTHER_PHONE_DISPLAY */ NULL
,
342 /* SIPE_BUDDY_INFO_CUSTOM1_PHONE */ NULL
,
343 /* SIPE_BUDDY_INFO_CUSTOM1_PHONE_DISPLAY */ NULL
,
346 static GPtrArray
*convert_contact_info(struct telepathy_buddy
*buddy
)
348 GPtrArray
*info
= NULL
;
353 info
= dbus_g_type_specialized_construct(
354 TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST
);
356 for (i
= 0; i
< SIPE_INFO_FIELD_MAX
; i
++) {
357 const gchar
*name
= sipe_to_vcard_field
[i
];
358 const gchar
*value
= buddy
->info
[i
];
361 const gchar
*const field_values
[2] = { value
, NULL
};
363 SIPE_DEBUG_INFO("SipeContactInfo::convert_contact_info: %s: (%2d)%s = '%s'",
364 buddy
->uri
, i
, name
, value
);
366 g_ptr_array_add(info
,
367 tp_value_array_build(3,
370 G_TYPE_STRV
, field_values
,
379 static void get_contact_info(TpSvcConnectionInterfaceContactInfo
*iface
,
380 const GArray
*contacts
,
381 DBusGMethodInvocation
*context
)
383 struct sipe_backend_private
*telepathy_private
= sipe_telepathy_connection_private(G_OBJECT(iface
));
384 GHashTable
*buddies
= telepathy_private
->contact_list
->buddy_handles
;
385 TpBaseConnection
*base
= TP_BASE_CONNECTION(iface
);
386 TpHandleRepoIface
*repo
= tp_base_connection_get_handles(base
,
387 TP_HANDLE_TYPE_CONTACT
);
388 GError
*error
= NULL
;
392 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base
, context
);
394 SIPE_DEBUG_INFO_NOFORMAT("SipeContactInfo::get_contact_info called");
396 if (!tp_handles_are_valid(repo
, contacts
, FALSE
, &error
)) {
397 dbus_g_method_return_error(context
, error
);
402 infos
= dbus_g_type_specialized_construct(TP_HASH_TYPE_CONTACT_INFO_MAP
);
404 for (i
= 0; i
< contacts
->len
; i
++) {
405 TpHandle contact
= g_array_index(contacts
, TpHandle
, i
);
406 struct telepathy_buddy
*buddy
= g_hash_table_lookup(buddies
,
407 GUINT_TO_POINTER(contact
));
408 GPtrArray
*info
= convert_contact_info(buddy
);
411 g_hash_table_insert(infos
,
412 GUINT_TO_POINTER(contact
),
416 tp_svc_connection_interface_contact_info_return_from_get_contact_info(context
,
418 g_boxed_free(TP_HASH_TYPE_CONTACT_INFO_MAP
, infos
);
421 static void request_contact_info(TpSvcConnectionInterfaceContactInfo
*iface
,
423 DBusGMethodInvocation
*context
)
425 struct sipe_backend_private
*telepathy_private
= sipe_telepathy_connection_private(G_OBJECT(iface
));
426 struct telepathy_buddy
*buddy
= g_hash_table_lookup(telepathy_private
->contact_list
->buddy_handles
,
427 GUINT_TO_POINTER(contact
));
428 TpBaseConnection
*base
= TP_BASE_CONNECTION(iface
);
429 TpHandleRepoIface
*repo
= tp_base_connection_get_handles(base
,
430 TP_HANDLE_TYPE_CONTACT
);
431 GError
*error
= NULL
;
434 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base
, context
);
436 SIPE_DEBUG_INFO_NOFORMAT("SipeContactInfo::request_contact_info called");
438 if (!tp_handle_is_valid(repo
, contact
, &error
)) {
439 dbus_g_method_return_error(context
, error
);
444 info
= convert_contact_info(buddy
);
446 dbus_g_method_return_error(context
, error
);
451 tp_svc_connection_interface_contact_info_return_from_request_contact_info(context
,
453 g_boxed_free(TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST
, info
);
456 void sipe_telepathy_contact_info_iface_init(gpointer g_iface
,
457 SIPE_UNUSED_PARAMETER gpointer iface_data
)
459 TpSvcConnectionInterfaceContactInfoClass
*klass
= g_iface
;
461 #define IMPLEMENT(x) tp_svc_connection_interface_contact_info_implement_##x( \
463 IMPLEMENT(get_contact_info
);
464 /* Information is provided by the server: can't implement
465 IMPLEMENT(refresh_contact_info); */
466 IMPLEMENT(request_contact_info
);
467 /* Information is provided by the server: can't implement
468 IMPLEMENT(set_contact_info); */
472 GPtrArray
*sipe_telepathy_contact_info_fields(void)
474 GPtrArray
*fields
= dbus_g_type_specialized_construct(TP_ARRAY_TYPE_FIELD_SPECS
);
477 SIPE_DEBUG_INFO_NOFORMAT("SipeContactInfo::contact_info_fields called");
479 for (i
= 0; i
<= SIPE_BUDDY_INFO_CUSTOM1_PHONE_DISPLAY
; i
++) {
480 const gchar
*vcard_name
= sipe_to_vcard_field
[i
];
483 /* unsupported field */
487 va
= tp_value_array_build(4,
488 G_TYPE_STRING
, vcard_name
,
490 G_TYPE_UINT
, 0, /* tp_flags */
491 G_TYPE_UINT
, 1, /* max_times */
493 g_ptr_array_add (fields
, va
);
499 /* TpDBusPropertiesMixinPropImpl is a broken typedef */
500 gpointer
sipe_telepathy_contact_info_props(void)
502 static TpDBusPropertiesMixinPropImpl props
[] = {
504 .name
= "ContactInfoFlags",
505 .getter_data
= GUINT_TO_POINTER(0),
506 /* @TODO .getter_data = GUINT_TO_POINTER(TP_CONTACT_INFO_FLAG_CAN_SET), */
510 .name
= "SupportedFields",
522 * Backend adaptor functions
524 sipe_backend_buddy
sipe_backend_buddy_find(struct sipe_core_public
*sipe_public
,
525 const gchar
*buddy_name
,
526 const gchar
*group_name
)
528 struct sipe_backend_private
*telepathy_private
= sipe_public
->backend_private
;
529 struct telepathy_buddy
*buddy
= g_hash_table_lookup(telepathy_private
->contact_list
->buddies
,
535 return(g_hash_table_lookup(buddy
->groups
, group_name
));
537 /* just return the first entry */
540 g_hash_table_iter_init(&iter
, buddy
->groups
);
541 g_hash_table_iter_next(&iter
, NULL
, &value
);
546 static GSList
*buddy_add_all(struct telepathy_buddy
*buddy
, GSList
*list
)
549 struct telepathy_buddy_entry
*buddy_entry
;
554 g_hash_table_iter_init(&iter
, buddy
->groups
);
555 while (g_hash_table_iter_next(&iter
, NULL
, (gpointer
) &buddy_entry
))
556 list
= g_slist_prepend(list
, buddy_entry
);
561 GSList
*sipe_backend_buddy_find_all(SIPE_UNUSED_PARAMETER
struct sipe_core_public
*sipe_public
,
562 const gchar
*buddy_name
,
563 const gchar
*group_name
)
565 GSList
*result
= NULL
;
567 /* NOTE: group_name != NULL not implemented in purple either */
569 struct sipe_backend_private
*telepathy_private
= sipe_public
->backend_private
;
570 GHashTable
*buddies
= telepathy_private
->contact_list
->buddies
;
573 result
= buddy_add_all(g_hash_table_lookup(buddies
,
577 GHashTableIter biter
;
578 struct telepathy_buddy
*buddy
;
580 g_hash_table_iter_init(&biter
, telepathy_private
->contact_list
->buddies
);
581 while (g_hash_table_iter_next(&biter
, NULL
, (gpointer
) &buddy
))
582 result
= buddy_add_all(buddy
, result
);
589 gchar
*sipe_backend_buddy_get_name(SIPE_UNUSED_PARAMETER
struct sipe_core_public
*sipe_public
,
590 const sipe_backend_buddy who
)
592 return(g_strdup(((struct telepathy_buddy_entry
*) who
)->buddy
->uri
));
595 gchar
*sipe_backend_buddy_get_alias(SIPE_UNUSED_PARAMETER
struct sipe_core_public
*sipe_public
,
596 const sipe_backend_buddy who
)
598 return(g_strdup(((struct telepathy_buddy_entry
*) who
)->buddy
->info
[SIPE_BUDDY_INFO_DISPLAY_NAME
]));
601 gchar
*sipe_backend_buddy_get_server_alias(struct sipe_core_public
*sipe_public
,
602 const sipe_backend_buddy who
)
604 /* server alias is the same as alias */
605 return(sipe_backend_buddy_get_alias(sipe_public
, who
));
608 gchar
*sipe_backend_buddy_get_local_alias(struct sipe_core_public
*sipe_public
,
609 const sipe_backend_buddy who
)
611 /* server alias is the same as alias */
612 return(sipe_backend_buddy_get_alias(sipe_public
, who
));
615 gchar
*sipe_backend_buddy_get_group_name(SIPE_UNUSED_PARAMETER
struct sipe_core_public
*sipe_public
,
616 const sipe_backend_buddy who
)
618 return(g_strdup(((struct telepathy_buddy_entry
*) who
)->group
));
621 gchar
*sipe_backend_buddy_get_string(SIPE_UNUSED_PARAMETER
struct sipe_core_public
*sipe_public
,
622 sipe_backend_buddy who
,
623 const sipe_buddy_info_fields key
)
625 struct telepathy_buddy_entry
*buddy_entry
= who
;
626 struct telepathy_buddy
*buddy
= buddy_entry
->buddy
;
628 if (key
>= SIPE_INFO_FIELD_MAX
)
630 return(g_strdup(buddy
->info
[key
]));
633 void sipe_backend_buddy_set_string(struct sipe_core_public
*sipe_public
,
634 sipe_backend_buddy who
,
635 const sipe_buddy_info_fields key
,
638 struct sipe_backend_private
*telepathy_private
= sipe_public
->backend_private
;
639 SipeContactList
*contact_list
= telepathy_private
->contact_list
;
640 struct telepathy_buddy_entry
*buddy_entry
= who
;
641 struct telepathy_buddy
*buddy
= buddy_entry
->buddy
;
643 if (key
>= SIPE_INFO_FIELD_MAX
)
646 SIPE_DEBUG_INFO("sipe_backend_buddy_set_string: %s replacing info %d: %s -> %s",
648 buddy
->info
[key
] ? buddy
->info
[key
]: "<UNDEFINED>",
651 g_free(buddy
->info
[key
]);
652 buddy
->info
[key
] = g_strdup(val
);
654 if (contact_list
->initial_received
) {
655 /* @TODO: emit signal? */
659 void sipe_backend_buddy_refresh_properties(struct sipe_core_public
*sipe_public
,
662 struct sipe_backend_private
*telepathy_private
= sipe_public
->backend_private
;
663 struct telepathy_buddy
*buddy
= g_hash_table_lookup(telepathy_private
->contact_list
->buddies
,
665 GPtrArray
*info
= convert_contact_info(buddy
);
668 tp_svc_connection_interface_contact_info_emit_contact_info_changed(telepathy_private
->connection
,
671 g_boxed_free(TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST
, info
);
675 guint
sipe_backend_buddy_get_status(struct sipe_core_public
*sipe_public
,
678 struct sipe_backend_private
*telepathy_private
= sipe_public
->backend_private
;
679 struct telepathy_buddy
*buddy
= g_hash_table_lookup(telepathy_private
->contact_list
->buddies
,
683 return(SIPE_ACTIVITY_UNSET
);
684 return(buddy
->activity
);
687 void sipe_backend_buddy_set_alias(struct sipe_core_public
*sipe_public
,
688 const sipe_backend_buddy who
,
691 struct sipe_backend_private
*telepathy_private
= sipe_public
->backend_private
;
692 SipeContactList
*contact_list
= telepathy_private
->contact_list
;
693 struct telepathy_buddy_entry
*buddy_entry
= who
;
694 struct telepathy_buddy
*buddy
= buddy_entry
->buddy
;
696 update_alias(buddy
, alias
);
698 if (contact_list
->initial_received
) {
699 SIPE_DEBUG_INFO("sipe_backend_buddy_set_alias: %s changed to '%s'",
701 sipe_telepathy_connection_alias_updated(contact_list
->connection
,
707 void sipe_backend_buddy_set_server_alias(SIPE_UNUSED_PARAMETER
struct sipe_core_public
*sipe_public
,
708 SIPE_UNUSED_PARAMETER
const sipe_backend_buddy who
,
709 SIPE_UNUSED_PARAMETER
const gchar
*alias
)
711 /* server alias is the same as alias. Ignore this */
714 void sipe_backend_buddy_list_processing_finish(struct sipe_core_public
*sipe_public
)
716 struct sipe_backend_private
*telepathy_private
= sipe_public
->backend_private
;
717 SipeContactList
*contact_list
= telepathy_private
->contact_list
;
719 if (!contact_list
->initial_received
) {
720 /* we can only call this once */
721 contact_list
->initial_received
= TRUE
;
722 SIPE_DEBUG_INFO_NOFORMAT("sipe_backend_buddy_list_processing_finish called");
723 tp_base_contact_list_set_list_received(TP_BASE_CONTACT_LIST(contact_list
));
727 static void buddy_free(gpointer data
)
729 struct telepathy_buddy
*buddy
= data
;
731 g_hash_table_destroy(buddy
->groups
);
732 for (i
= 0; i
< SIPE_INFO_FIELD_MAX
; i
++)
733 g_free(buddy
->info
[i
]);
738 sipe_backend_buddy
sipe_backend_buddy_add(struct sipe_core_public
*sipe_public
,
741 const gchar
*group_name
)
743 struct sipe_backend_private
*telepathy_private
= sipe_public
->backend_private
;
744 SipeContactList
*contact_list
= telepathy_private
->contact_list
;
745 const gchar
*group
= g_hash_table_lookup(contact_list
->groups
,
747 struct telepathy_buddy
*buddy
= g_hash_table_lookup(contact_list
->buddies
,
749 struct telepathy_buddy_entry
*buddy_entry
;
755 buddy
= g_new0(struct telepathy_buddy
, 1);
756 buddy
->uri
= g_strdup(name
); /* reused as key */
757 buddy
->groups
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
759 buddy
->info
[SIPE_BUDDY_INFO_DISPLAY_NAME
] = g_strdup(alias
);
761 buddy
->activity
= SIPE_ACTIVITY_OFFLINE
;
762 buddy
->handle
= tp_handle_ensure(contact_list
->contact_repo
,
763 buddy
->uri
, NULL
, NULL
);
764 tp_handle_set_add(contact_list
->contacts
, buddy
->handle
);
765 g_hash_table_insert(contact_list
->buddies
,
766 (gchar
*) buddy
->uri
, /* owned by hash table */
768 g_hash_table_insert(contact_list
->buddy_handles
,
769 GUINT_TO_POINTER(buddy
->handle
),
773 buddy_entry
= g_hash_table_lookup(buddy
->groups
, group
);
775 buddy_entry
= g_new0(struct telepathy_buddy_entry
, 1);
776 buddy_entry
->buddy
= buddy
;
777 buddy_entry
->group
= group
;
778 g_hash_table_insert(buddy
->groups
,
779 (gchar
*) group
, /* key is borrowed */
783 if (contact_list
->initial_received
) {
784 /* @TODO: emit signal? */
790 void sipe_backend_buddy_remove(struct sipe_core_public
*sipe_public
,
791 const sipe_backend_buddy who
)
793 struct sipe_backend_private
*telepathy_private
= sipe_public
->backend_private
;
794 SipeContactList
*contact_list
= telepathy_private
->contact_list
;
795 struct telepathy_buddy_entry
*remove_entry
= who
;
796 struct telepathy_buddy
*buddy
= remove_entry
->buddy
;
798 g_hash_table_remove(buddy
->groups
,
799 remove_entry
->group
);
800 /* remove_entry is invalid */
802 if (g_hash_table_size(buddy
->groups
) == 0) {
803 /* removed from last group -> drop this buddy */
804 tp_handle_set_remove(contact_list
->contacts
,
806 g_hash_table_remove(contact_list
->buddy_handles
,
807 GUINT_TO_POINTER(buddy
->handle
));
808 g_hash_table_remove(contact_list
->buddies
,
813 if (contact_list
->initial_received
) {
814 /* @TODO: emit signal? */
818 void sipe_backend_buddy_set_status(struct sipe_core_public
*sipe_public
,
822 struct sipe_backend_private
*telepathy_private
= sipe_public
->backend_private
;
823 SipeContactList
*contact_list
= telepathy_private
->contact_list
;
824 struct telepathy_buddy
*buddy
= g_hash_table_lookup(contact_list
->buddies
,
826 TpPresenceStatus
*status
;
830 buddy
->activity
= activity
;
832 SIPE_DEBUG_INFO("sipe_backend_buddy_set_status: %s to %d", uri
, activity
);
834 /* emit status update signal */
835 status
= tp_presence_status_new(activity
, NULL
);
836 tp_presence_mixin_emit_one_presence_update(G_OBJECT(telepathy_private
->connection
),
837 buddy
->handle
, status
);
838 tp_presence_status_free(status
);
841 gboolean
sipe_backend_uses_photo(void)
846 void sipe_backend_buddy_set_photo(struct sipe_core_public
*sipe_public
,
850 const gchar
*photo_hash
)
852 struct sipe_backend_private
*telepathy_private
= sipe_public
->backend_private
;
853 struct telepathy_buddy
*buddy
= g_hash_table_lookup(telepathy_private
->contact_list
->buddies
,
857 char *hash_file
= g_build_filename(telepathy_private
->cache_dir
,
861 /* does this buddy already have a photo? -> delete it */
863 char *photo_file
= g_build_filename(telepathy_private
->cache_dir
,
866 g_remove(photo_file
);
872 /* update hash file */
873 if (g_file_set_contents(hash_file
,
877 char *photo_file
= g_build_filename(telepathy_private
->cache_dir
,
880 buddy
->hash
= g_strdup(photo_hash
);
881 g_file_set_contents(photo_file
,
886 /* @TODO: trigger avatar update/creation */
897 const gchar
*sipe_backend_buddy_get_photo_hash(struct sipe_core_public
*sipe_public
,
900 struct sipe_backend_private
*telepathy_private
= sipe_public
->backend_private
;
901 struct telepathy_buddy
*buddy
= g_hash_table_lookup(telepathy_private
->contact_list
->buddies
,
908 char *hash_file
= g_build_filename(telepathy_private
->cache_dir
,
911 /* returned memory is owned & freed by buddy */
912 if (g_file_get_contents(hash_file
, &buddy
->hash
, NULL
, NULL
)) {
913 /* @TODO: trigger creation of avatar for buddy */
921 gboolean
sipe_backend_buddy_group_add(struct sipe_core_public
*sipe_public
,
922 const gchar
*group_name
)
924 struct sipe_backend_private
*telepathy_private
= sipe_public
->backend_private
;
925 SipeContactList
*contact_list
= telepathy_private
->contact_list
;
926 gchar
*group
= g_hash_table_lookup(contact_list
->groups
,
930 group
= g_strdup(group_name
);
931 g_hash_table_insert(contact_list
->groups
, group
, group
);
932 tp_base_contact_list_groups_created(TP_BASE_CONTACT_LIST(contact_list
),
937 return(group
!= NULL
);
940 void sipe_backend_buddy_group_remove(struct sipe_core_public
*sipe_public
,
941 const gchar
*group_name
)
943 struct sipe_backend_private
*telepathy_private
= sipe_public
->backend_private
;
944 SipeContactList
*contact_list
= telepathy_private
->contact_list
;
946 g_hash_table_remove(contact_list
->groups
, group_name
);
948 if (contact_list
->initial_received
) {
949 /* @TODO: emit signal? */