From e5b06bf62b3661c2bfb88040444f40a0e8afa0f7 Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Mon, 10 Sep 2012 21:46:54 +0300 Subject: [PATCH] core: process incoming changes for roaming contacts If the user uses more than one client then updates to the buddy list done in one client will be sent as NOTIFY/roaming-contacts+xml to the others. The XML root is "contactDelta". Added support for - group renaming - buddy alias update - buddy added to group - buddy removed from group Not implemented yet - new group - group deleted - buddy deleted Introduced new backend API sipe_backend_buddy_group_rename() to support renaming of groups. Supplied a functional implementation for purple and dummy stubs for miranda & telepathy. --- src/api/sipe-backend.h | 12 +++ src/core/sipe-buddy.c | 35 ++++---- src/core/sipe-buddy.h | 11 ++- src/core/sipe-group.c | 16 +++- src/core/sipe-group.h | 7 +- src/core/sipe-notify.c | 178 ++++++++++++++++++++++++++++++++++++++++ src/miranda/miranda-buddy.c | 8 ++ src/purple/purple-buddy.c | 10 +++ src/telepathy/telepathy-stubs.c | 3 + 9 files changed, 261 insertions(+), 19 deletions(-) diff --git a/src/api/sipe-backend.h b/src/api/sipe-backend.h index 0fcc6e8c..40b6f974 100644 --- a/src/api/sipe-backend.h +++ b/src/api/sipe-backend.h @@ -919,6 +919,18 @@ gboolean sipe_backend_buddy_group_add(struct sipe_core_public *sipe_public, const gchar *group_name); /** + * Called when a new internal group has been renamed + * + * @param sipe_public The handle representing the protocol instance making the call + * @param old_name old name of the group + * @param new_name new name of the group + * @return TRUE if the group was found and renamed + */ +gboolean sipe_backend_buddy_group_rename(struct sipe_core_public *sipe_public, + const gchar *old_name, + const gchar *new_name); + +/** * Present requested buddy information to the user */ struct sipe_backend_buddy_info; diff --git a/src/core/sipe-buddy.c b/src/core/sipe-buddy.c index 3db0e123..b8eebdd3 100644 --- a/src/core/sipe-buddy.c +++ b/src/core/sipe-buddy.c @@ -244,6 +244,18 @@ void sipe_core_buddy_add(struct sipe_core_public *sipe_public, group_name); } +void sipe_buddy_remove(struct sipe_core_private *sipe_private, + struct sipe_buddy *buddy) +{ + gchar *action_name = sipe_utils_presence_key(buddy->name); + sipe_schedule_cancel(sipe_private, action_name); + g_free(action_name); + + g_hash_table_remove(sipe_private->buddies, buddy->name); + + buddy_free(buddy); +} + /** * Unassociates buddy from group first. * Then see if no groups left, removes buddy completely. @@ -270,22 +282,13 @@ void sipe_core_buddy_remove(struct sipe_core_public *sipe_public, } if (g_slist_length(b->groups) < 1) { - gchar *action_name = sipe_utils_presence_key(uri); - sipe_schedule_cancel(sipe_private, action_name); - g_free(action_name); - - g_hash_table_remove(sipe_private->buddies, uri); - - if (b->name) { - gchar *request = g_strdup_printf("%s", - b->name); - sip_soap_request(sipe_private, - "deleteContact", - request); - g_free(request); - } - - buddy_free(b); + gchar *request = g_strdup_printf("%s", + b->name); + sip_soap_request(sipe_private, + "deleteContact", + request); + g_free(request); + sipe_buddy_remove(sipe_private, b); } else { /* updates groups on server */ sipe_core_group_set_user(sipe_public, b->name); diff --git a/src/core/sipe-buddy.h b/src/core/sipe-buddy.h index 02afe8e9..94a733d0 100644 --- a/src/core/sipe-buddy.h +++ b/src/core/sipe-buddy.h @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2010 SIPE Project + * Copyright (C) 2010-12 SIPE Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -72,6 +72,15 @@ struct sipe_buddy *sipe_buddy_add(struct sipe_core_private *sipe_private, const gchar *uri); /** + * Cancels buddy subscriptions and then deletes the buddy + * + * @param sipe_private SIPE core data + * @param buddy @c sipe_buddy structure to remove + */ +void sipe_buddy_remove(struct sipe_core_private *sipe_private, + struct sipe_buddy *buddy); + +/** * Free all buddy information * * @param sipe_private SIPE core data diff --git a/src/core/sipe-group.c b/src/core/sipe-group.c index 456fea21..0589dc9e 100755 --- a/src/core/sipe-group.c +++ b/src/core/sipe-group.c @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2011 SIPE Project + * Copyright (C) 2011-12 SIPE Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -177,6 +177,20 @@ sipe_group_create(struct sipe_core_private *sipe_private, g_free(request); } +gboolean sipe_group_rename(struct sipe_core_private *sipe_private, + struct sipe_group *group, + const gchar *name) +{ + gboolean renamed = sipe_backend_buddy_group_rename(SIPE_CORE_PUBLIC, + group->name, + name); + if (renamed) { + g_free(group->name); + group->name = g_strdup(name); + } + return(renamed); +} + void sipe_group_add(struct sipe_core_private *sipe_private, struct sipe_group * group) diff --git a/src/core/sipe-group.h b/src/core/sipe-group.h index 96b5746b..8616bc21 100644 --- a/src/core/sipe-group.h +++ b/src/core/sipe-group.h @@ -3,7 +3,7 @@ * * pidgin-sipe * - * Copyright (C) 2011 SIPE Project + * Copyright (C) 2011-12 SIPE Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,6 +36,11 @@ void sipe_group_create(struct sipe_core_private *sipe_private, const gchar *name, const gchar * who); +gboolean sipe_group_rename(struct sipe_core_private *sipe_private, + struct sipe_group *group, + const gchar *name); + void sipe_group_add(struct sipe_core_private *sipe_private, struct sipe_group * group); + diff --git a/src/core/sipe-notify.c b/src/core/sipe-notify.c index e7dcd5f6..bfe0d10d 100644 --- a/src/core/sipe-notify.c +++ b/src/core/sipe-notify.c @@ -1235,6 +1235,184 @@ static gboolean sipe_process_roaming_contacts(struct sipe_core_private *sipe_pri /* Finished processing contact list */ sipe_backend_buddy_list_processing_finish(SIPE_CORE_PUBLIC); + + } else if (sipe_strequal(sipe_xml_name(isc), "contactDelta")) { + + /* @TODO: Parse new groups + * + * + */ + for (group_node = sipe_xml_child(isc, "addedGroup"); group_node; group_node = sipe_xml_twin(group_node)) { + const char *name = sipe_xml_attribute(group_node, "name"); + SIPE_DEBUG_INFO("Add new group '%s' - NOT IMPLEMENTED", name); + } + + /* Parse modified groups */ + for (group_node = sipe_xml_child(isc, "modifiedGroup"); group_node; group_node = sipe_xml_twin(group_node)) { + struct sipe_group *group = sipe_group_find_by_id(sipe_private, + (int)g_ascii_strtod(sipe_xml_attribute(group_node, "id"), + NULL)); + if (group) { + const char *name = sipe_xml_attribute(group_node, "name"); + + if (g_str_has_prefix(name, "~")) { + name = _("Other Contacts"); + } + + if (!(is_empty(name) || + sipe_strequal(group->name, name)) && + sipe_group_rename(sipe_private, + group, + name)) + SIPE_DEBUG_INFO("Replaced group %d name with %s", group->id, name); + } + } + + /* @TODO: Parse deleted groups + * + * + */ + for (group_node = sipe_xml_child(isc, "deletedGroup"); group_node; group_node = sipe_xml_twin(group_node)) { + const char *id = sipe_xml_attribute(group_node, "id"); + SIPE_DEBUG_INFO("Delete group ID %s - NOT IMPLEMENTED", id); + } + + /* @TODO: Parse new buddies + * + * + */ + for (item = sipe_xml_child(isc, "addedContact"); item; item = sipe_xml_twin(item)) { + const gchar *uri = sipe_xml_attribute(item, "uri"); + SIPE_DEBUG_INFO("Add new buddy %s - NOT IMPLEMENTED", uri); + } + + /* Parse modified contacts */ + for (item = sipe_xml_child(isc, "modifiedContact"); item; item = sipe_xml_twin(item)) { + const gchar *uri = sipe_xml_attribute(item, "uri"); + struct sipe_buddy *buddy = g_hash_table_lookup(sipe_private->buddies, + uri); + + if (buddy) { + sipe_backend_buddy b = sipe_backend_buddy_find(SIPE_CORE_PUBLIC, + uri, + NULL); + + if (b) { + const gchar *name = sipe_xml_attribute(item, "name"); + gchar *b_alias = sipe_backend_buddy_get_alias(SIPE_CORE_PUBLIC, + b); + gchar **item_groups; + int i = 0; + GSList *found = NULL; + GSList *entry; + + /* new alias? */ + if (!(is_empty(name) || + sipe_strequal(b_alias, name))) { + sipe_backend_buddy_set_alias(SIPE_CORE_PUBLIC, + b, + name); + SIPE_DEBUG_INFO("Replaced buddy %s alias with %s", b_alias, name); + } + g_free(b_alias); + + item_groups = g_strsplit(sipe_xml_attribute(item, + "groups"), + " ", 0); + /* added to groups? */ + if (item_groups) { + while (item_groups[i]) { + struct sipe_group *group = sipe_group_find_by_id(sipe_private, + g_ascii_strtod(item_groups[i], + NULL)); + + /* ignore unkown groups */ + if (group) { + sipe_backend_buddy oldb = sipe_backend_buddy_find(SIPE_CORE_PUBLIC, + uri, + group->name); + + /* add group to found list */ + found = g_slist_prepend(found, group); + + /* buddy NOT in this group? */ + if (!oldb) { + b_alias = sipe_backend_buddy_get_alias(SIPE_CORE_PUBLIC, + b); + SIPE_DEBUG_INFO("Adding buddy %s (alias %s) to new group %s", uri, b_alias, group->name); + sipe_backend_buddy_add(SIPE_CORE_PUBLIC, + uri, + b_alias, + group->name); + g_free(b_alias); + + buddy->groups = slist_insert_unique_sorted(buddy->groups, + group, + (GCompareFunc) sipe_group_compare); + } + } + + /* next group */ + i++; + } + g_strfreev(item_groups); + } + + /* removed from groups? */ + entry = buddy->groups; + while (entry) { + GSList *remove_link = entry; + struct sipe_group *group = remove_link->data; + + /* next buddy group */ + entry = entry->next; + + /* old group NOT found in new list? */ + if (g_slist_find(found, group) == NULL) { + sipe_backend_buddy oldb = sipe_backend_buddy_find(SIPE_CORE_PUBLIC, + uri, + group->name); + SIPE_DEBUG_INFO("Removing buddy %s from group %s", uri, group->name); + /* this should never be NULL */ + if (oldb) + sipe_backend_buddy_remove(SIPE_CORE_PUBLIC, + oldb); + buddy->groups = g_slist_remove_link(buddy->groups, + remove_link); + } + } + g_slist_free(found); + } + } + } + + /* Parse deleted contacts */ + for (item = sipe_xml_child(isc, "deletedContact"); item; item = sipe_xml_twin(item)) { + const gchar *uri = sipe_xml_attribute(item, "uri"); + struct sipe_buddy *buddy = g_hash_table_lookup(sipe_private->buddies, + uri); + + if (buddy) { + GSList *entry = buddy->groups; + + SIPE_DEBUG_INFO("Removing buddy %s", uri); + while (entry) { + struct sipe_group *group = entry->data; + sipe_backend_buddy oldb = sipe_backend_buddy_find(SIPE_CORE_PUBLIC, + uri, + group->name); + /* this should never be NULL */ + if (oldb) + sipe_backend_buddy_remove(SIPE_CORE_PUBLIC, + oldb); + + /* next buddy group */ + entry = entry->next; + } + sipe_buddy_remove(sipe_private, buddy); + } + } + } sipe_xml_free(isc); diff --git a/src/miranda/miranda-buddy.c b/src/miranda/miranda-buddy.c index ad0f527a..8a00eeba 100644 --- a/src/miranda/miranda-buddy.c +++ b/src/miranda/miranda-buddy.c @@ -511,6 +511,14 @@ gboolean sipe_backend_buddy_group_add(struct sipe_core_public *sipe_public, return (hGroup?TRUE:FALSE); } +gboolean sipe_backend_buddy_group_rename(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public, + SIPE_UNUSED_PARAMETER const gchar *old_name, + SIPE_UNUSED_PARAMETER const gchar *new_name) +{ + /* @TODO */ + return(FALSE); +} + struct sipe_backend_buddy_info *sipe_backend_buddy_info_start(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public) { return((struct sipe_backend_buddy_info *)g_hash_table_new_full(NULL,NULL,NULL,g_free)); diff --git a/src/purple/purple-buddy.c b/src/purple/purple-buddy.c index 9e0dc2fc..55895820 100644 --- a/src/purple/purple-buddy.c +++ b/src/purple/purple-buddy.c @@ -332,6 +332,16 @@ gboolean sipe_backend_buddy_group_add(SIPE_UNUSED_PARAMETER struct sipe_core_pub return (purple_group != NULL); } +gboolean sipe_backend_buddy_group_rename(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public, + const gchar *old_name, + const gchar *new_name) +{ + PurpleGroup *purple_group = purple_find_group(old_name); + if (purple_group) + purple_blist_rename_group(purple_group, new_name); + return(purple_group != NULL); +} + struct sipe_backend_buddy_info *sipe_backend_buddy_info_start(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public) { return((struct sipe_backend_buddy_info *)purple_notify_user_info_new()); diff --git a/src/telepathy/telepathy-stubs.c b/src/telepathy/telepathy-stubs.c index d6498570..076000c2 100644 --- a/src/telepathy/telepathy-stubs.c +++ b/src/telepathy/telepathy-stubs.c @@ -71,6 +71,9 @@ void sipe_backend_buddy_set_photo(SIPE_UNUSED_PARAMETER struct sipe_core_public SIPE_UNUSED_PARAMETER const gchar *photo_hash) {} const gchar *sipe_backend_buddy_get_photo_hash(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public, SIPE_UNUSED_PARAMETER const gchar *who) { return(""); } +gboolean sipe_backend_buddy_group_rename(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public, + SIPE_UNUSED_PARAMETER const gchar *old_name, + SIPE_UNUSED_PARAMETER const gchar *new_name) { return(FALSE); } struct sipe_backend_buddy_info *sipe_backend_buddy_info_start(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public) { return(NULL); } void sipe_backend_buddy_info_add(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public, SIPE_UNUSED_PARAMETER struct sipe_backend_buddy_info *info, -- 2.11.4.GIT