/soc/2012/tomkiewicz/gg: 42bbe5b85df8: Gadu-Gadu: roster - uploa...
Tomasz Wasilczyk
tomkiewicz at cpw.pidgin.im
Thu Jul 12 05:03:26 EDT 2012
Changeset: 42bbe5b85df8d5499cce50e95ec6de2e432b9a96
Author: Tomasz Wasilczyk <tomkiewicz at cpw.pidgin.im>
Date: 2012-07-12 11:03 +0200
Branch: soc.2012.gg
URL: http://hg.pidgin.im/soc/2012/tomkiewicz/gg/rev/42bbe5b85df8
Description:
Gadu-Gadu: roster - uploading/synchronization - part1
diffstat:
libpurple/protocols/gg/gg.c | 7 +-
libpurple/protocols/gg/roster.c | 504 ++++++++++++++++++++++++++++++++++++---
libpurple/protocols/gg/roster.h | 11 +-
libpurple/protocols/gg/xml.c | 45 +++
libpurple/protocols/gg/xml.h | 6 +
5 files changed, 519 insertions(+), 54 deletions(-)
diffs (truncated from 818 to 300 lines):
diff --git a/libpurple/protocols/gg/gg.c b/libpurple/protocols/gg/gg.c
--- a/libpurple/protocols/gg/gg.c
+++ b/libpurple/protocols/gg/gg.c
@@ -1196,8 +1196,7 @@
ggp_events_user_data(gc, &ev->event.user_data);
break;
case GG_EVENT_USERLIST100_VERSION:
- purple_debug_info("gg", "GG_EVENT_USERLIST100_VERSION: %u\n",
- ev->event.userlist100_version.version);
+ ggp_roster_version(gc, &ev->event.userlist100_version);
break;
case GG_EVENT_USERLIST100_REPLY:
ggp_roster_reply(gc, &ev->event.userlist100_reply);
@@ -2181,8 +2180,8 @@
ggp_keepalive, /* keepalive */
ggp_account_register, /* register_user */
NULL, /* get_cb_info */
- NULL, /* alias_buddy */
- NULL, /* group_buddy */
+ ggp_roster_alias_buddy, /* alias_buddy */
+ ggp_roster_group_buddy, /* group_buddy */
NULL, /* rename_group */
NULL, /* buddy_free */
NULL, /* convo_closed */
diff --git a/libpurple/protocols/gg/roster.c b/libpurple/protocols/gg/roster.c
--- a/libpurple/protocols/gg/roster.c
+++ b/libpurple/protocols/gg/roster.c
@@ -7,17 +7,74 @@
#include <debug.h>
#define GGP_ROSTER_SYNC_SETT "gg-synchronized"
+#define GGP_ROSTER_ID_SETT "gg-id"
#define GGP_ROSTER_DEBUG 1
+#define GGP_ROSTER_GROUP_DEFAULT _("Buddies")
+#define GGP_ROSTER_GROUPID_DEFAULT "00000000-0000-0000-0000-000000000000"
-static void ggp_roster_set_synchronized(PurpleBuddy *buddy, gboolean synchronized);
+/*
+ TODO:
+
+- remove_group
+- auto-sync at startup
+- group rename (w obie strony; rename_group)
+- buddy removal
+
+*/
+
+typedef struct
+{
+ xmlnode *xml;
+
+ xmlnode *groups_node, *contacts_node;
+
+ /**
+ * Key: (uin_t) user identifier
+ * Value: (xmlnode*) xml node for contact
+ */
+ GHashTable *contact_nodes;
+
+ /**
+ * Key: (gchar*) group id
+ * Value: (xmlnode*) xml node for group
+ */
+ GHashTable *group_nodes;
+
+ gboolean needs_update;
+} ggp_roster_content;
+
+typedef struct
+{
+ enum
+ {
+ GGP_ROSTER_CHANGE_CONTACT_UPDATE,
+ GGP_ROSTER_CHANGE_CONTACT_REMOVE,
+ } type;
+ union
+ {
+ uin_t uin;
+ } data;
+} ggp_roster_change;
+
+static void ggp_roster_content_free(ggp_roster_content *content);
+static void ggp_roster_change_free(gpointer change);
+
static gboolean ggp_roster_is_synchronized(PurpleBuddy *buddy);
+static void ggp_roster_set_synchronized(PurpleConnection *gc, PurpleBuddy *buddy, gboolean synchronized);
+static const gchar * ggp_roster_add_group(ggp_roster_content *content, PurpleGroup *group);
+static gboolean ggp_roster_timer_cb(gpointer _gc);
+
+static void ggp_roster_reply_ack(PurpleConnection *gc, uint32_t version);
static void ggp_roster_reply_list(PurpleConnection *gc, uint32_t version, const char *reply);
+static void ggp_roster_send_update(PurpleConnection *gc);
#if GGP_ROSTER_DEBUG
-static void ggp_roster_dump(PurpleConnection *gc);
+static void ggp_roster_dump(ggp_roster_content *content);
#endif
+static void ggp_roster_set_not_synchronized(PurpleConnection *gc, const char *who);
+
/********/
static inline ggp_roster_session_data *
@@ -31,33 +88,85 @@
{
ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
- rdata->xml = NULL;
rdata->version = 0;
+ rdata->content = NULL;
+ rdata->sent_updates = NULL;
+ rdata->pending_updates = NULL;
+
+ rdata->timer = purple_timeout_add_seconds(1, ggp_roster_timer_cb, gc); //TODO: 10s / check for value in original gg
}
void ggp_roster_cleanup(PurpleConnection *gc)
{
ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
- if (rdata->xml)
- xmlnode_free(rdata->xml);
+ purple_timeout_remove(rdata->timer);
+ ggp_roster_content_free(rdata->content);
+ g_list_free_full(rdata->sent_updates, ggp_roster_change_free);
+ g_list_free_full(rdata->pending_updates, ggp_roster_change_free);
}
-static void ggp_roster_set_synchronized(PurpleBuddy *buddy, gboolean synchronized)
+static void ggp_roster_content_free(ggp_roster_content *content)
{
- purple_blist_node_set_bool((PurpleBlistNode*)buddy, GGP_ROSTER_SYNC_SETT, synchronized);
+ if (content == NULL)
+ return;
+ if (content->xml)
+ xmlnode_free(content->xml);
+ if (content->contact_nodes)
+ g_hash_table_destroy(content->contact_nodes);
+ if (content->group_nodes)
+ g_hash_table_destroy(content->group_nodes);
+ g_free(content);
+}
+
+static void ggp_roster_change_free(gpointer _change)
+{
+ ggp_roster_change *change = _change;
+ g_free(change);
+}
+
+static void ggp_roster_set_synchronized(PurpleConnection *gc, PurpleBuddy *buddy, gboolean synchronized)
+{
+ ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
+ uin_t uin = ggp_str_to_uin(purple_buddy_get_name(buddy));
+ ggp_roster_change *change;
+
+ purple_debug_info("gg", "ggp_roster_set_synchronized [uin=%u, sync=%d]\n", uin, synchronized);
+
+ purple_blist_node_set_bool(PURPLE_BLIST_NODE(buddy), GGP_ROSTER_SYNC_SETT, synchronized);
+ if (!synchronized)
+ {
+ change = g_new(ggp_roster_change, 1);
+ change->type = GGP_ROSTER_CHANGE_CONTACT_UPDATE;
+ change->data.uin = uin;
+ rdata->pending_updates = g_list_append(rdata->pending_updates, change);
+ }
}
static gboolean ggp_roster_is_synchronized(PurpleBuddy *buddy)
{
- return purple_blist_node_get_bool((PurpleBlistNode*)buddy, GGP_ROSTER_SYNC_SETT);
+ gboolean ret = purple_blist_node_get_bool(PURPLE_BLIST_NODE(buddy), GGP_ROSTER_SYNC_SETT);
+ purple_debug_info("gg", "ggp_roster_is_synchronized [uin=%s, sync=%d]\n", purple_buddy_get_name(buddy), ret);
+ return ret;
+}
+
+static gboolean ggp_roster_timer_cb(gpointer _gc)
+{
+ PurpleConnection *gc = _gc;
+
+ g_return_val_if_fail(PURPLE_CONNECTION_IS_VALID(gc), FALSE);
+
+ ggp_roster_send_update(gc);
+
+ return TRUE;
}
void ggp_roster_update(PurpleConnection *gc)
{
GGPInfo *accdata = purple_connection_get_protocol_data(gc);
+ ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
- purple_debug_info("gg", "ggp_roster_update\n");
+ purple_debug_info("gg", "ggp_roster_update [local: %u]\n", rdata->version);
if (!gg_libgadu_check_feature(GG_LIBGADU_FEATURE_USERLIST100))
{
@@ -65,35 +174,110 @@
return;
}
- gg_userlist100_request(accdata->session, GG_USERLIST100_GET, 0, GG_USERLIST100_FORMAT_TYPE_GG100, NULL);
+ gg_userlist100_request(accdata->session, GG_USERLIST100_GET, rdata->version, GG_USERLIST100_FORMAT_TYPE_GG100, NULL);
}
void ggp_roster_reply(PurpleConnection *gc, struct gg_event_userlist100_reply *reply)
{
- purple_debug_info("gg", "ggp_roster_reply [type=%d, version=%u, format_type=%d]\n",
+ purple_debug_info("gg", "ggp_roster_reply [type=%x, version=%u, format_type=%x]\n",
reply->type, reply->version, reply->format_type);
-
- if (reply->type != GG_USERLIST100_REPLY_LIST)
- return;
-
+
if (GG_USERLIST100_FORMAT_TYPE_GG100 != reply->format_type)
{
- purple_debug_warning("gg", "ggp_buddylist_load100_reply: unsupported format type (%u)\n", reply->format_type);
+ purple_debug_warning("gg", "ggp_roster_reply: unsupported format type (%x)\n", reply->format_type);
return;
}
- ggp_roster_reply_list(gc, reply->version, reply->reply);
+ if (reply->type == GG_USERLIST100_REPLY_LIST)
+ ggp_roster_reply_list(gc, reply->version, reply->reply);
+ else if (reply->type == 0x01) // list up to date (TODO: push to libgadu)
+ purple_debug_info("gg", "ggp_roster_reply: list up to date\n");
+ else if (reply->type == GG_USERLIST100_REPLY_ACK)
+ ggp_roster_reply_ack(gc, reply->version);
+ else if (reply->type == GG_USERLIST100_REPLY_REJECT)
+ purple_debug_error("gg", "ggp_roster_reply: not implemented (reject)\n");
+ else
+ purple_debug_error("gg", "ggp_roster_reply: unsupported reply (%x)\n", reply->type);
+}
+
+void ggp_roster_version(PurpleConnection *gc, struct gg_event_userlist100_version *version)
+{
+ ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
+ int local_version = rdata->version;
+ int remote_version = version->version;
+
+ purple_debug_info("gg", "ggp_roster_version [local=%u, remote=%u]\n", local_version, remote_version);
+
+ if (local_version < remote_version)
+ ggp_roster_update(gc);
+}
+
+static void ggp_roster_reply_ack(PurpleConnection *gc, uint32_t version)
+{
+ PurpleAccount *account = purple_connection_get_account(gc);
+ ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
+ ggp_roster_content *content = rdata->content;
+
+ // set synchronization flag for all buddies, that were updated at roster
+ GList *updates_it = g_list_first(rdata->sent_updates);
+ while (updates_it)
+ {
+ ggp_roster_change *change = updates_it->data;
+ PurpleBuddy *buddy;
+ updates_it = g_list_next(updates_it);
+
+ if (change->type != GGP_ROSTER_CHANGE_CONTACT_UPDATE)
+ continue;
+
+ buddy = purple_find_buddy(account, ggp_uin_to_str(change->data.uin));
+ if (buddy)
+ ggp_roster_set_synchronized(gc, buddy, TRUE);
+ }
+
+ // we need to remove "synchronized" flag for all contacts, that have
+ // beed modified between roster update start and now
+ updates_it = g_list_first(rdata->pending_updates);
+ while (updates_it)
+ {
+ ggp_roster_change *change = updates_it->data;
+ PurpleBuddy *buddy;
+ updates_it = g_list_next(updates_it);
+
+ if (change->type != GGP_ROSTER_CHANGE_CONTACT_UPDATE)
+ continue;
+
+ buddy = purple_find_buddy(account, ggp_uin_to_str(change->data.uin));
+ if (buddy && ggp_roster_is_synchronized(buddy))
+ ggp_roster_set_synchronized(gc, buddy, FALSE);
+ }
+
+ g_list_free_full(rdata->sent_updates, ggp_roster_change_free);
+ rdata->sent_updates = NULL;
+
+ // bump roster version or update it, if needed
+ g_return_if_fail(content != NULL);
+ if (content->needs_update)
+ {
+ ggp_roster_content_free(rdata->content);
+ rdata->content = NULL;
+ // we have to wait for gg_event_userlist100_version
+ //ggp_roster_update(gc);
+ }
+ else
+ rdata->version = version;
More information about the Commits
mailing list