cpw.darkrain42.xmpp.roster: b4776a1c: A clunky attempt to track roster subscri...

darkrain42 at pidgin.im darkrain42 at pidgin.im
Tue Jan 12 22:56:58 EST 2010


-----------------------------------------------------------------
Revision: b4776a1cbbcc566564678032d094cc560701f4f6
Ancestor: d5a2e2287440ac7134c201e66921754bd4187ba9
Author: darkrain42 at pidgin.im
Date: 2010-01-13T03:00:55
Branch: im.pidgin.cpw.darkrain42.xmpp.roster
URL: http://d.pidgin.im/viewmtn/revision/info/b4776a1cbbcc566564678032d094cc560701f4f6

Modified files:
        libpurple/protocols/jabber/buddy.c
        libpurple/protocols/jabber/buddy.h
        libpurple/protocols/jabber/jabber.c
        libpurple/protocols/jabber/jutil.c
        libpurple/protocols/jabber/jutil.h
        libpurple/protocols/jabber/presence.c
        libpurple/protocols/jabber/roster.c
        libpurple/protocols/jabber/si.c

ChangeLog: 

A clunky attempt to track roster subscriptions with roster versioning enabled.

There are, I believe, two remaining issues here:
  * All uses of jabber_buddy_find(js, ..., FALSE) need to be audited, as
    users on the roster aren't pre-created.
  * jabber_roster_add_buddy() needs to check all instances of the PurpleBuddy
    for subscription state (and sync to this instance), as this could be
	a new PB for a pre-existing contact.

This would be so much cleaner if the core had a concept of subscription state
(or a model of one PurpleBuddy per contact).  Refs #10935.

-------------- next part --------------
============================================================
--- libpurple/protocols/jabber/buddy.c	0c8b7646ec51795cd8296b341efde6504c1e7035
+++ libpurple/protocols/jabber/buddy.c	5b85dfcc3506b32d145244de8f8569139f9018ac
@@ -1814,6 +1814,7 @@ static GList *jabber_buddy_menu(PurpleBu
 	PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(buddy));
 	JabberStream *js = purple_connection_get_protocol_data(gc);
 	const char *name = purple_buddy_get_name(buddy);
+	JabberSubscription subscription = jabber_subscription_from_buddy(buddy);
 	JabberBuddy *jb = jabber_buddy_find(js, name, TRUE);
 	GList *jbrs;
 
@@ -1836,14 +1837,14 @@ static GList *jabber_buddy_menu(PurpleBu
 		m = g_list_append(m, act);
 	}
 
-	if(jb->subscription & JABBER_SUB_FROM && jb != js->user_jb) {
+	if (subscription & JABBER_SUB_FROM && jb != js->user_jb) {
 		act = purple_menu_action_new(_("Cancel Presence Notification"),
 		                           PURPLE_CALLBACK(jabber_buddy_cancel_presence_notification),
 		                           NULL, NULL);
 		m = g_list_append(m, act);
 	}
 
-	if(!(jb->subscription & JABBER_SUB_TO)) {
+	if (!(subscription & JABBER_SUB_TO)) {
 		act = purple_menu_action_new(_("(Re-)Request authorization"),
 		                           PURPLE_CALLBACK(jabber_buddy_rerequest_auth),
 		                           NULL, NULL);
============================================================
--- libpurple/protocols/jabber/buddy.h	509699775bb00c543db2320f5098bc63aa66d78d
+++ libpurple/protocols/jabber/buddy.h	1d06efcbf7c1b1a795a8b5580b936289193bdf14
@@ -48,14 +48,6 @@ struct _JabberBuddy {
 		JABBER_INVISIBLE_SERVER = 1 << 1,
 		JABBER_INVIS_BUDDY      = 1 << 2
 	} invisible;
-	enum {
-		JABBER_SUB_NONE    = 0,
-		JABBER_SUB_PENDING = 1 << 1,
-		JABBER_SUB_TO      = 1 << 2,
-		JABBER_SUB_FROM    = 1 << 3,
-		JABBER_SUB_BOTH    = (JABBER_SUB_TO | JABBER_SUB_FROM),
-		JABBER_SUB_REMOVE  = 1 << 4
-	} subscription;
 };
 
 typedef struct _JabberAdHocCommands {
============================================================
--- libpurple/protocols/jabber/jabber.c	3f8dd3c03faffaf7c79505103730b4ed8b2a4621
+++ libpurple/protocols/jabber/jabber.c	ead612d51ed5353a009fbf91569370601d74eeba
@@ -121,6 +121,23 @@ static void jabber_session_init(JabberSt
 	jabber_iq_send(iq);
 }
 
+static void
+update_self_contact_subscriptions(JabberStream *js, const char *jid)
+{
+	PurpleAccount *account = purple_connection_get_account(js->gc);
+	GSList *buddies = purple_find_buddies(account, jid);
+
+	while (buddies) {
+		PurpleBlistNode *bnode = buddies->data;
+		if (!purple_strequal(purple_blist_node_get_string(bnode, "subscription"), "both"))
+			purple_blist_node_set_string(bnode, "subscription", "both");
+		if (purple_blist_node_get_bool(bnode, "subscription_pending"))
+			purple_blist_node_set_bool(bnode, "subscription_pending", FALSE);
+
+		buddies = g_slist_delete_link(buddies, buddies);
+	}
+}
+
 static void jabber_bind_result_cb(JabberStream *js, const char *from,
                                   JabberIqType type, const char *id,
                                   xmlnode *packet, gpointer data)
@@ -144,7 +161,7 @@ static void jabber_bind_result_cb(Jabber
 			}
 
 			js->user_jb = jabber_buddy_find(js, full_jid, TRUE);
-			js->user_jb->subscription |= JABBER_SUB_BOTH;
+			update_self_contact_subscriptions(js, full_jid);
 
 			purple_connection_set_display_name(js->gc, full_jid);
 
@@ -842,7 +859,7 @@ jabber_stream_new(PurpleAccount *account
 		g_return_val_if_reached(NULL);
 	}
 
-	js->user_jb->subscription |= JABBER_SUB_BOTH;
+	update_self_contact_subscriptions(js, user);
 
 	js->iq_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal,
 			g_free, g_free);
@@ -1907,9 +1924,12 @@ const char* jabber_list_emblem(PurpleBud
 		jb = jabber_buddy_find(js, purple_buddy_get_name(b), FALSE);
 
 	if(!PURPLE_BUDDY_IS_ONLINE(b)) {
-		if(jb && (jb->subscription & JABBER_SUB_PENDING ||
-					!(jb->subscription & JABBER_SUB_TO)))
-			return "not-authorized";
+		if (jb && jb != js->user_jb) {
+			JabberSubscription subscription = jabber_subscription_from_buddy(b);
+			if ((subscription & JABBER_SUB_PENDING) ||
+					!(subscription & JABBER_SUB_TO))
+				return "not-authorized";
+		}
 	}
 
 	if (jb) {
@@ -1939,18 +1959,27 @@ char *jabber_status_text(PurpleBuddy *b)
 char *jabber_status_text(PurpleBuddy *b)
 {
 	char *ret = NULL;
-	JabberBuddy *jb = NULL;
 	PurpleAccount *account = purple_buddy_get_account(b);
 	PurpleConnection *gc = purple_account_get_connection(account);
+	JabberStream *js = NULL;
+	JabberBuddy *jb = NULL;
 
-	if (gc && gc->proto_data)
-		jb = jabber_buddy_find(gc->proto_data, purple_buddy_get_name(b), FALSE);
+	if (gc)
+		js = purple_connection_get_protocol_data(gc);
 
-	if(jb && !PURPLE_BUDDY_IS_ONLINE(b) && (jb->subscription & JABBER_SUB_PENDING || !(jb->subscription & JABBER_SUB_TO))) {
-		ret = g_strdup(_("Not Authorized"));
-	} else if(jb && !PURPLE_BUDDY_IS_ONLINE(b) && jb->error_msg) {
-		ret = g_strdup(jb->error_msg);
-	} else {
+	if (js)
+		jb = jabber_buddy_find(js, purple_buddy_get_name(b), FALSE);
+
+	if (jb && jb != js->user_jb && !PURPLE_BUDDY_IS_ONLINE(b)) {
+		JabberSubscription subscription = jabber_subscription_from_buddy(b);
+		if ((subscription & JABBER_SUB_PENDING) || !(subscription & JABBER_SUB_TO)) {
+			ret = g_strdup(_("Not Authorized"));
+		} else if (jb->error_msg) {
+			ret = g_strdup(jb->error_msg);
+		}
+	}
+
+	if (!ret) {
 		PurplePresence *presence = purple_buddy_get_presence(b);
 		PurpleStatus *status = purple_presence_get_active_status(presence);
 		const char *message;
@@ -2019,6 +2048,7 @@ void jabber_tooltip_text(PurpleBuddy *b,
 	JabberBuddy *jb;
 	PurpleAccount *account;
 	PurpleConnection *gc;
+	JabberStream *js = NULL;
 
 	g_return_if_fail(b != NULL);
 
@@ -2027,9 +2057,10 @@ void jabber_tooltip_text(PurpleBuddy *b,
 
 	gc = purple_account_get_connection(account);
 	g_return_if_fail(gc != NULL);
-	g_return_if_fail(gc->proto_data != NULL);
+	g_return_if_fail(purple_connection_get_protocol_data(gc) != NULL);
 
-	jb = jabber_buddy_find(gc->proto_data, purple_buddy_get_name(b), FALSE);
+	js = purple_connection_get_protocol_data(gc);
+	jb = jabber_buddy_find(js, purple_buddy_get_name(b), FALSE);
 
 	if(jb) {
 		JabberBuddyResource *jbr = NULL;
@@ -2058,6 +2089,7 @@ void jabber_tooltip_text(PurpleBuddy *b,
 
 		if (full) {
 			PurpleStatus *status;
+			JabberSubscription subscription = jabber_subscription_from_buddy(b);
 
 			status = purple_presence_get_active_status(presence);
 			mood = purple_status_get_attr_string(status, "mood");
@@ -2084,17 +2116,17 @@ void jabber_tooltip_text(PurpleBuddy *b,
 				}
 			}
 
-			if(jb->subscription & JABBER_SUB_FROM) {
-				if(jb->subscription & JABBER_SUB_TO)
+			if (subscription & JABBER_SUB_FROM) {
+				if (subscription & JABBER_SUB_TO)
 					sub = _("Both");
-				else if(jb->subscription & JABBER_SUB_PENDING)
+				else if (subscription & JABBER_SUB_PENDING)
 					sub = _("From (To pending)");
 				else
 					sub = _("From");
 			} else {
-				if(jb->subscription & JABBER_SUB_TO)
+				if (subscription & JABBER_SUB_TO)
 					sub = _("To");
-				else if(jb->subscription & JABBER_SUB_PENDING)
+				else if (subscription & JABBER_SUB_PENDING)
 					sub = _("None (To pending)");
 				else
 					sub = _("None");
@@ -3000,8 +3032,8 @@ jabber_initiate_media(PurpleAccount *acc
 		      PurpleMediaSessionType type)
 {
 #ifdef USE_VV
-	JabberStream *js = (JabberStream *)
-			purple_account_get_connection(account)->proto_data;
+	JabberStream *js = purple_connection_get_protocol_data(
+			purple_account_get_connection(account));
 	JabberBuddy *jb;
 	JabberBuddyResource *jbr = NULL;
 	char *resource;
@@ -3036,11 +3068,16 @@ jabber_initiate_media(PurpleAccount *acc
 		/* no resources online, we're trying to initiate with someone
 		 * whose presence we're not subscribed to, or
 		 * someone who is offline.  Let's inform the user */
+		PurpleBuddy *buddy = purple_find_buddy(account, who);
+		JabberSubscription subscription = JABBER_SUB_NONE;
 		char *msg;
 
+		if (buddy)
+			subscription = jabber_subscription_from_buddy(buddy);
+
 		if(!jb) {
 			msg = g_strdup_printf(_("Unable to initiate media with %s: invalid JID"), who);
-		} else if(jb->subscription & JABBER_SUB_TO) {
+		} else if (subscription & JABBER_SUB_TO) {
 			msg = g_strdup_printf(_("Unable to initiate media with %s: user is not online"), who);
 		} else {
 			msg = g_strdup_printf(_("Unable to initiate media with %s: not subscribed to user presence"), who);
============================================================
--- libpurple/protocols/jabber/jutil.c	99af4534d0e0e24e6e0acd64e06d681311e59078
+++ libpurple/protocols/jabber/jutil.c	a75d5ed68ff704d8c27cc1314405ee30356d9661
@@ -670,6 +670,59 @@ jabber_find_unnormalized_conv(const char
 	return NULL;
 }
 
+const char *
+jabber_subscription_to_string(JabberSubscription sub)
+{
+	sub = sub & ~JABBER_SUB_PENDING;
+
+	if (sub == JABBER_SUB_BOTH)
+		return "both";
+	else if (sub == JABBER_SUB_FROM)
+		return "from";
+	else if (sub == JABBER_SUB_TO)
+		return "to";
+	else if (JABBER_SUB_NONE)
+		return "none";
+
+	purple_debug_warning("jabber", "Unknown JabberSubscription value %d\n", sub);
+	return "none";
+}
+
+JabberSubscription
+jabber_subscription_from_string(const char *str)
+{
+	JabberSubscription subscription = JABBER_SUB_NONE;
+
+	if (str) {
+		if (g_str_equal(str, "to"))
+			subscription = JABBER_SUB_TO;
+		else if (g_str_equal(str, "from"))
+			subscription = JABBER_SUB_FROM;
+		else if (g_str_equal(str, "both"))
+			subscription = JABBER_SUB_BOTH;
+	}
+
+	return subscription;
+}
+
+JabberSubscription
+jabber_subscription_from_buddy(PurpleBuddy *buddy)
+{
+	const char *sub;
+	gboolean pending;
+	JabberSubscription subscription = JABBER_SUB_NONE;
+
+	sub = purple_blist_node_get_string(PURPLE_BLIST_NODE(buddy), "subscription");
+	pending = purple_blist_node_get_bool(PURPLE_BLIST_NODE(buddy), "subscription_pending");
+
+	if (sub)
+		subscription = jabber_subscription_from_string(sub);
+	if (pending)
+		subscription |= JABBER_SUB_PENDING;
+
+	return subscription;
+}
+
 /* The same as purple_util_get_image_checksum, but guaranteed to remain SHA1 */
 char *
 jabber_calculate_data_sha1sum(gconstpointer data, size_t len)
============================================================
--- libpurple/protocols/jabber/jutil.h	868ace1b7d30296ddba8ba5b105198a5c97ddc12
+++ libpurple/protocols/jabber/jutil.h	883402184c515f3ce1a27815c6a24b4d578a027e
@@ -30,6 +30,14 @@ typedef struct _JabberID {
 	char *resource;
 } JabberID;
 
+typedef enum {
+	JABBER_SUB_NONE    = 0,
+	JABBER_SUB_PENDING = 1 << 1,
+	JABBER_SUB_TO      = 1 << 2,
+	JABBER_SUB_FROM    = 1 << 3,
+	JABBER_SUB_BOTH    = (JABBER_SUB_TO | JABBER_SUB_FROM)
+} JabberSubscription;
+
 #include "jabber.h"
 
 JabberID* jabber_id_new(const char *str);
@@ -65,5 +73,9 @@ PurpleConversation *jabber_find_unnormal
 
 PurpleConversation *jabber_find_unnormalized_conv(const char *name, PurpleAccount *account);
 
+const gchar *jabber_subscription_to_string(JabberSubscription sub);
+JabberSubscription jabber_subscription_from_string(const char *str);
+JabberSubscription jabber_subscription_from_buddy(PurpleBuddy *buddy);
+
 char *jabber_calculate_data_sha1sum(gconstpointer data, size_t len);
 #endif /* PURPLE_JABBER_JUTIL_H_ */
============================================================
--- libpurple/protocols/jabber/presence.c	2f5c934a28b8a0bcb26cdf7a249b7fc7832458ad
+++ libpurple/protocols/jabber/presence.c	2a3f0a1fa7054e58331d35a8acb9a4604f3c1717
@@ -561,7 +561,6 @@ void jabber_presence_parse(JabberStream 
 		gboolean onlist = FALSE;
 		PurpleAccount *account;
 		PurpleBuddy *buddy;
-		JabberBuddy *jb = NULL;
 		xmlnode *nick;
 
 		account = purple_connection_get_account(js->gc);
@@ -571,8 +570,8 @@ void jabber_presence_parse(JabberStream 
 			nickname = xmlnode_get_data(nick);
 
 		if (buddy) {
-			jb = jabber_buddy_find(js, from, TRUE);
-			if ((jb->subscription & (JABBER_SUB_TO | JABBER_SUB_PENDING)))
+			JabberSubscription subscription = jabber_subscription_from_buddy(buddy);
+			if (subscription & (JABBER_SUB_TO | JABBER_SUB_PENDING))
 				onlist = TRUE;
 		}
 
============================================================
--- libpurple/protocols/jabber/roster.c	71d568bb2d7e1cd166f30864723b0089da7d3dce
+++ libpurple/protocols/jabber/roster.c	daed8902e128dab4bab51b0cce8f4e921cc94161
@@ -77,13 +77,16 @@ void jabber_roster_request(JabberStream 
 void jabber_roster_request(JabberStream *js)
 {
 	PurpleAccount *account;
+	const char *ver;
 	JabberIq *iq;
 	xmlnode *query;
 
 	account = purple_connection_get_account(js->gc);
+	ver = purple_account_get_string(account, "roster_ver", "");
 
 	iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:roster");
 	query = xmlnode_get_child(iq->node, "query");
+	xmlnode_set_attrib(query, "ver", ver);
 
 	if (js->server_caps & JABBER_CAP_GOOGLE_ROSTER) {
 		xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER);
@@ -107,12 +110,12 @@ static void add_purple_buddy_to_groups(J
 }
 
 static void add_purple_buddy_to_groups(JabberStream *js, const char *jid,
-		const char *alias, GSList *groups)
+		const char *alias, JabberSubscription subscription, GSList *groups)
 {
 	GSList *buddies, *l;
 	PurpleAccount *account = purple_connection_get_account(js->gc);
 
-	buddies = purple_find_buddies(js->gc->account, jid);
+	buddies = purple_find_buddies(account, jid);
 
 	if(!groups) {
 		if(!buddies)
@@ -141,16 +144,22 @@ static void add_purple_buddy_to_groups(J
 		 */
 		if((l = g_slist_find_custom(groups, purple_group_get_name(g), (GCompareFunc)purple_utf8_strcasecmp))) {
 			/* The buddy is already on the local list. Update info. */
+			PurpleBlistNode *bnode = PURPLE_BLIST_NODE(b);
 			const char *servernick, *balias;
 
 			/* Previously stored serverside / buddy-supplied alias */
-			if((servernick = purple_blist_node_get_string((PurpleBlistNode*)b, "servernick")))
+			if((servernick = purple_blist_node_get_string(bnode, "servernick")))
 				serv_got_alias(js->gc, jid, servernick);
 
 			/* Alias from our roster retrieval */
 			balias = purple_buddy_get_local_buddy_alias(b);
 			if(alias && !purple_strequal(alias, balias))
 				purple_serv_got_private_alias(js->gc, jid, alias);
+
+			/* Subscription status */
+			purple_blist_node_set_string(bnode, "subscription", jabber_subscription_to_string(subscription));
+			purple_blist_node_set_bool(bnode, "subscription_pending", (subscription & JABBER_SUB_PENDING));
+
 			g_free(l->data);
 			groups = g_slist_delete_link(groups, l);
 		} else {
@@ -209,6 +218,8 @@ void jabber_roster_parse(JabberStream *j
 	{
 		const char *jid, *name, *subscription, *ask;
 		JabberBuddy *jb;
+		gboolean remove = FALSE;
+		JabberSubscription sub = JABBER_SUB_NONE;
 
 		subscription = xmlnode_get_attrib(item, "subscription");
 		jid = xmlnode_get_attrib(item, "jid");
@@ -221,27 +232,19 @@ void jabber_roster_parse(JabberStream *j
 		if(!(jb = jabber_buddy_find(js, jid, TRUE)))
 			continue;
 
-		if(subscription) {
+		if (subscription) {
 			if (g_str_equal(subscription, "remove"))
-				jb->subscription = JABBER_SUB_REMOVE;
-			else if (jb == js->user_jb)
-				jb->subscription = JABBER_SUB_BOTH;
-			else if (g_str_equal(subscription, "none"))
-				jb->subscription = JABBER_SUB_NONE;
-			else if (g_str_equal(subscription, "to"))
-				jb->subscription = JABBER_SUB_TO;
-			else if (g_str_equal(subscription, "from"))
-				jb->subscription = JABBER_SUB_FROM;
-			else if (g_str_equal(subscription, "both"))
-				jb->subscription = JABBER_SUB_BOTH;
+				remove = TRUE;
+			else
+				sub = jabber_subscription_from_string(subscription);
 		}
 
 		if(purple_strequal(ask, "subscribe"))
-			jb->subscription |= JABBER_SUB_PENDING;
+			sub |= JABBER_SUB_PENDING;
 		else
-			jb->subscription &= ~JABBER_SUB_PENDING;
+			sub &= ~JABBER_SUB_PENDING;
 
-		if(jb->subscription & JABBER_SUB_REMOVE) {
+		if (remove) {
 			remove_purple_buddies(js, jid);
 		} else {
 			GSList *groups = NULL;
@@ -262,7 +265,7 @@ void jabber_roster_parse(JabberStream *j
 				groups = g_slist_prepend(groups, group_name);
 			}
 
-			add_purple_buddy_to_groups(js, jid, name, groups);
+			add_purple_buddy_to_groups(js, jid, name, sub, groups);
 			if (jb == js->user_jb)
 				jabber_presence_fake_to_self(js, NULL);
 		}
@@ -354,6 +357,7 @@ void jabber_roster_add_buddy(PurpleConne
 	JabberID *jid;
 	JabberBuddy *jb;
 	JabberBuddyResource *jbr;
+	JabberSubscription subscription;
 	const char *name;
 
 	/* If we haven't received the roster yet, ignore any adds */
@@ -397,9 +401,11 @@ void jabber_roster_add_buddy(PurpleConne
 
 	jabber_roster_update(js, who, NULL);
 
+	subscription = jabber_subscription_from_buddy(buddy);
+
 	if (jb == js->user_jb) {
 		jabber_presence_fake_to_self(js, NULL);
-	} else if(!jb || !(jb->subscription & JABBER_SUB_TO)) {
+	} else if (!jb || !(subscription & JABBER_SUB_TO)) {
 		jabber_presence_subscription_set(js, who, "subscribe");
 	} else if((jbr =jabber_buddy_find_resource(jb, NULL))) {
 		purple_prpl_got_user_status(gc->account, who,
============================================================
--- libpurple/protocols/jabber/si.c	04dcf15bf4537fe1f17570752ee39f81e49c6bb1
+++ libpurple/protocols/jabber/si.c	a6a0daf121bd9b4f0fd307a1416b87807b5ccfe2
@@ -1504,11 +1504,17 @@ static void jabber_si_xfer_init(PurpleXf
 			/* no resources online, we're trying to send to someone
 			 * whose presence we're not subscribed to, or
 			 * someone who is offline.  Let's inform the user */
+			PurpleBuddy *buddy;
+			JabberSubscription subscription = JABBER_SUB_NONE;
 			char *msg;
 
+			buddy = purple_find_buddy(purple_xfer_get_account(xfer), purple_xfer_get_remote_user(xfer));
+			if (buddy)
+				subscription = jabber_subscription_from_buddy(buddy);
+
 			if(!jb) {
 				msg = g_strdup_printf(_("Unable to send file to %s, invalid JID"), xfer->who);
-			} else if(jb->subscription & JABBER_SUB_TO) {
+			} else if(subscription & JABBER_SUB_TO) {
 				msg = g_strdup_printf(_("Unable to send file to %s, user is not online"), xfer->who);
 			} else {
 				msg = g_strdup_printf(_("Unable to send file to %s, not subscribed to user presence"), xfer->who);


More information about the Commits mailing list