/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