changeset 29454:5c9c4557fec2

merge of '20a2cebedc53676ed04bba9375a4e5a9cd97b6fd' and 'c0adc68d6e21c013beb36f789a05d94234c3696a'
author Paul Aurich <paul@darkrain42.org>
date Tue, 16 Feb 2010 15:16:28 +0000
parents 89f072f356ef (diff) e4cf053a1d7a (current diff)
children 28714ff543cd 9c5158a62705 e446b56c01e4 cc6d733a192a
files
diffstat 4 files changed, 167 insertions(+), 182 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/jabber/buddy.c	Tue Feb 16 08:38:20 2010 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Tue Feb 16 15:16:28 2010 +0000
@@ -57,6 +57,36 @@
 	gchar *last_message;
 } JabberBuddyInfo;
 
+static void
+jabber_buddy_resource_free(JabberBuddyResource *jbr)
+{
+	g_return_if_fail(jbr != NULL);
+
+	jbr->jb->resources = g_list_remove(jbr->jb->resources, jbr);
+
+	while(jbr->commands) {
+		JabberAdHocCommands *cmd = jbr->commands->data;
+		g_free(cmd->jid);
+		g_free(cmd->node);
+		g_free(cmd->name);
+		g_free(cmd);
+		jbr->commands = g_list_delete_link(jbr->commands, jbr->commands);
+	}
+
+	while (jbr->caps.exts) {
+		g_free(jbr->caps.exts->data);
+		jbr->caps.exts = g_list_delete_link(jbr->caps.exts, jbr->caps.exts);
+	}
+
+	g_free(jbr->name);
+	g_free(jbr->status);
+	g_free(jbr->thread_id);
+	g_free(jbr->client.name);
+	g_free(jbr->client.version);
+	g_free(jbr->client.os);
+	g_free(jbr);
+}
+
 void jabber_buddy_free(JabberBuddy *jb)
 {
 	g_return_if_fail(jb != NULL);
@@ -91,6 +121,10 @@
 	return jb;
 }
 
+/* Returns -1 if a is a higher priority resource than b, or is
+ * "more available" than b.  0 if they're the same, and 1 if b is
+ * higher priority/more available than a.
+ */
 static gint resource_compare_cb(gconstpointer a, gconstpointer b)
 {
 	const JabberBuddyResource *jbra = a;
@@ -98,9 +132,10 @@
 	JabberBuddyState state_a, state_b;
 
 	if (jbra->priority != jbrb->priority)
-		return jbra->priority > jbrb->priority ? 1 : -1;
+		return jbra->priority > jbrb->priority ? -1 : 1;
 
 	/* Fold the states for easier comparison */
+	/* TODO: Differentiate online/chat and away/dnd? */
 	switch (jbra->state) {
 		case JABBER_BUDDY_STATE_ONLINE:
 		case JABBER_BUDDY_STATE_CHAT:
@@ -146,105 +181,74 @@
 			return 0;
 		else if ((jbra->idle && !jbrb->idle) ||
 				(jbra->idle && jbrb->idle && jbra->idle < jbrb->idle))
-			return -1;
+			return 1;
 		else
-			return 1;
+			return -1;
 	}
 
 	if (state_a == JABBER_BUDDY_STATE_ONLINE)
-		return 1;
+		return -1;
 	else if (state_a == JABBER_BUDDY_STATE_AWAY &&
 				(state_b == JABBER_BUDDY_STATE_XA ||
 				 state_b == JABBER_BUDDY_STATE_UNAVAILABLE ||
 				 state_b == JABBER_BUDDY_STATE_UNKNOWN))
-		return 1;
+		return -1;
 	else if (state_a == JABBER_BUDDY_STATE_XA &&
 				(state_b == JABBER_BUDDY_STATE_UNAVAILABLE ||
 				 state_b == JABBER_BUDDY_STATE_UNKNOWN))
-		return 1;
+		return -1;
 	else if (state_a == JABBER_BUDDY_STATE_UNAVAILABLE &&
 				state_b == JABBER_BUDDY_STATE_UNKNOWN)
-		return 1;
+		return -1;
 
-	return -1;
+	return 1;
 }
 
 JabberBuddyResource *jabber_buddy_find_resource(JabberBuddy *jb,
 		const char *resource)
 {
-	JabberBuddyResource *jbr = NULL;
 	GList *l;
 
-	if(!jb)
+	if (!jb)
 		return NULL;
 
-	for(l = jb->resources; l; l = l->next)
+	if (resource == NULL)
+		return jb->resources ? jb->resources->data : NULL;
+
+	for (l = jb->resources; l; l = l->next)
 	{
-		JabberBuddyResource *tmp = (JabberBuddyResource *) l->data;
-		if (!jbr && !resource) {
-			jbr = tmp;
-		} else if (!resource) {
-			if (resource_compare_cb(tmp, jbr) > 0)
-				jbr = tmp;
-		} else if(tmp->name) {
-			if(!strcmp(tmp->name, resource)) {
-				jbr = tmp;
-				break;
-			}
-		}
+		JabberBuddyResource *jbr = l->data;
+		if (g_str_equal(resource, jbr->name))
+			return jbr;
 	}
 
-	return jbr;
+	return NULL;
 }
 
 JabberBuddyResource *jabber_buddy_track_resource(JabberBuddy *jb, const char *resource,
 		int priority, JabberBuddyState state, const char *status)
 {
+	/* TODO: Optimization: Only reinsert if priority+state changed */
 	JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, resource);
-	if(!jbr) {
+	if (jbr) {
+		jb->resources = g_list_remove(jb->resources, jbr);
+	} else {
 		jbr = g_new0(JabberBuddyResource, 1);
 		jbr->jb = jb;
 		jbr->name = g_strdup(resource);
 		jbr->capabilities = JABBER_CAP_NONE;
 		jbr->tz_off = PURPLE_NO_TZ_OFF;
-		jb->resources = g_list_append(jb->resources, jbr);
 	}
 	jbr->priority = priority;
 	jbr->state = state;
 	g_free(jbr->status);
 	jbr->status = g_strdup(status);
 
+	jb->resources = g_list_insert_sorted(jb->resources, jbr,
+	                                     resource_compare_cb);
 	return jbr;
 }
 
-void jabber_buddy_resource_free(JabberBuddyResource *jbr)
-{
-	g_return_if_fail(jbr != NULL);
-
-	jbr->jb->resources = g_list_remove(jbr->jb->resources, jbr);
-
-	while(jbr->commands) {
-		JabberAdHocCommands *cmd = jbr->commands->data;
-		g_free(cmd->jid);
-		g_free(cmd->node);
-		g_free(cmd->name);
-		g_free(cmd);
-		jbr->commands = g_list_delete_link(jbr->commands, jbr->commands);
-	}
-
-	if (jbr->caps.exts) {
-		g_list_foreach(jbr->caps.exts, (GFunc)g_free, NULL);
-		g_list_free(jbr->caps.exts);
-	}
-	g_free(jbr->name);
-	g_free(jbr->status);
-	g_free(jbr->thread_id);
-	g_free(jbr->client.name);
-	g_free(jbr->client.version);
-	g_free(jbr->client.os);
-	g_free(jbr);
-}
-
 void jabber_buddy_remove_resource(JabberBuddy *jb, const char *resource)
 {
 	JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, resource);
@@ -797,6 +801,8 @@
 		jbr = jabber_buddy_find_resource(jbi->jb, resource_name);
 		add_jbr_info(jbi, resource_name, jbr);
 	} else {
+		/* TODO: This is in priority-ascending order (lowest prio first), because
+		 * everything is prepended.  Is that ok? */
 		for (resources = jbi->jb->resources; resources; resources = resources->next) {
 			jbr = resources->data;
 
@@ -1909,116 +1915,6 @@
 }
 
 
-const char *
-jabber_buddy_state_get_name(JabberBuddyState state)
-{
-	switch(state) {
-		case JABBER_BUDDY_STATE_UNKNOWN:
-			return _("Unknown");
-		case JABBER_BUDDY_STATE_ERROR:
-			return _("Error");
-		case JABBER_BUDDY_STATE_UNAVAILABLE:
-			return _("Offline");
-		case JABBER_BUDDY_STATE_ONLINE:
-			return _("Available");
-		case JABBER_BUDDY_STATE_CHAT:
-			return _("Chatty");
-		case JABBER_BUDDY_STATE_AWAY:
-			return _("Away");
-		case JABBER_BUDDY_STATE_XA:
-			return _("Extended Away");
-		case JABBER_BUDDY_STATE_DND:
-			return _("Do Not Disturb");
-	}
-
-	return _("Unknown");
-}
-
-JabberBuddyState jabber_buddy_status_id_get_state(const char *id) {
-	if(!id)
-		return JABBER_BUDDY_STATE_UNKNOWN;
-	if(!strcmp(id, "available"))
-		return JABBER_BUDDY_STATE_ONLINE;
-	if(!strcmp(id, "freeforchat"))
-		return JABBER_BUDDY_STATE_CHAT;
-	if(!strcmp(id, "away"))
-		return JABBER_BUDDY_STATE_AWAY;
-	if(!strcmp(id, "extended_away"))
-		return JABBER_BUDDY_STATE_XA;
-	if(!strcmp(id, "dnd"))
-		return JABBER_BUDDY_STATE_DND;
-	if(!strcmp(id, "offline"))
-		return JABBER_BUDDY_STATE_UNAVAILABLE;
-	if(!strcmp(id, "error"))
-		return JABBER_BUDDY_STATE_ERROR;
-
-	return JABBER_BUDDY_STATE_UNKNOWN;
-}
-
-const struct {
-	const char *name;
-	JabberBuddyState state;
-} show_state_pairs[] = {
-	{ "available", JABBER_BUDDY_STATE_ONLINE },
-	{ "chat",      JABBER_BUDDY_STATE_CHAT },
-	{ "away",      JABBER_BUDDY_STATE_AWAY },
-	{ "xa",        JABBER_BUDDY_STATE_XA },
-	{ "dnd",       JABBER_BUDDY_STATE_DND },
-	{ "offline",   JABBER_BUDDY_STATE_UNAVAILABLE },
-	{ "error",     JABBER_BUDDY_STATE_ERROR },
-	{ NULL,        JABBER_BUDDY_STATE_UNKNOWN }
-};
-
-JabberBuddyState jabber_buddy_show_get_state(const char *id)
-{
-	int i;
-
-	g_return_val_if_fail(id != NULL, JABBER_BUDDY_STATE_UNKNOWN);
-
-	for (i = 0; show_state_pairs[i].name; ++i)
-		if (g_str_equal(id, show_state_pairs[i].name))
-			return show_state_pairs[i].state;
-
-	purple_debug_warning("jabber", "Invalid value of presence <show/> "
-	                     "attribute: %s\n", id);
-	return JABBER_BUDDY_STATE_UNKNOWN;
-}
-
-const char *
-jabber_buddy_state_get_show(JabberBuddyState state)
-{
-	int i;
-
-	for (i = 0; show_state_pairs[i].name; ++i)
-		if (state == show_state_pairs[i].state)
-			return show_state_pairs[i].name;
-
-/*	purple_debug_warning("jabber", "Unknown buddy state: %d\n", state); */
-	return NULL;
-}
-
-const char *jabber_buddy_state_get_status_id(JabberBuddyState state) {
-	switch(state) {
-		case JABBER_BUDDY_STATE_CHAT:
-			return "freeforchat";
-		case JABBER_BUDDY_STATE_AWAY:
-			return "away";
-		case JABBER_BUDDY_STATE_XA:
-			return "extended_away";
-		case JABBER_BUDDY_STATE_DND:
-			return "dnd";
-		case JABBER_BUDDY_STATE_ONLINE:
-			return "available";
-		case JABBER_BUDDY_STATE_UNKNOWN:
-			return "available";
-		case JABBER_BUDDY_STATE_ERROR:
-			return "error";
-		case JABBER_BUDDY_STATE_UNAVAILABLE:
-			return "offline";
-	}
-	return NULL;
-}
-
 static void user_search_result_add_buddy_cb(PurpleConnection *gc, GList *row, void *user_data)
 {
 	/* XXX find out the jid */
--- a/libpurple/protocols/jabber/buddy.h	Tue Feb 16 08:38:20 2010 +0000
+++ b/libpurple/protocols/jabber/buddy.h	Tue Feb 16 15:16:28 2010 +0000
@@ -24,23 +24,20 @@
 #ifndef PURPLE_JABBER_BUDDY_H_
 #define PURPLE_JABBER_BUDDY_H_
 
-typedef enum {
-	JABBER_BUDDY_STATE_UNKNOWN = -2,
-	JABBER_BUDDY_STATE_ERROR = -1,
-	JABBER_BUDDY_STATE_UNAVAILABLE = 0,
-	JABBER_BUDDY_STATE_ONLINE,
-	JABBER_BUDDY_STATE_CHAT,
-	JABBER_BUDDY_STATE_AWAY,
-	JABBER_BUDDY_STATE_XA,
-	JABBER_BUDDY_STATE_DND
-} JabberBuddyState;
-
 typedef struct _JabberBuddy JabberBuddy;
 
 #include "jabber.h"
 #include "caps.h"
+#include "jutil.h"
 
 struct _JabberBuddy {
+	/**
+	 * A sorted list of resources in priority descending order.
+	 * This means that the first resource in the list is the
+	 * "most available" (see resource_compare_cb in buddy.c for
+	 * details).  Don't play with this yourself, let
+	 * jabber_buddy_track_resource and jabber_buddy_remove_resource do it.
+	 */
 	GList *resources;
 	char *error_msg;
 	enum {
@@ -100,7 +97,6 @@
 		const char *resource);
 JabberBuddyResource *jabber_buddy_track_resource(JabberBuddy *jb, const char *resource,
 		int priority, JabberBuddyState state, const char *status);
-void jabber_buddy_resource_free(JabberBuddyResource *jbr);
 void jabber_buddy_remove_resource(JabberBuddy *jb, const char *resource);
 void jabber_buddy_get_info(PurpleConnection *gc, const char *who);
 
@@ -110,12 +106,6 @@
 void jabber_setup_set_info(PurplePluginAction *action);
 void jabber_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img);
 
-const char *jabber_buddy_state_get_name(JabberBuddyState state);
-const char *jabber_buddy_state_get_status_id(JabberBuddyState state);
-const char *jabber_buddy_state_get_show(JabberBuddyState state);
-JabberBuddyState jabber_buddy_status_id_get_state(const char *id);
-JabberBuddyState jabber_buddy_show_get_state(const char *id);
-
 void jabber_user_search(JabberStream *js, const char *directory);
 void jabber_user_search_begin(PurplePluginAction *);
 
--- a/libpurple/protocols/jabber/jutil.c	Tue Feb 16 08:38:20 2010 +0000
+++ b/libpurple/protocols/jabber/jutil.c	Tue Feb 16 15:16:28 2010 +0000
@@ -651,6 +651,83 @@
 	return equal;
 }
 
+static const struct {
+		const char *status_id; /* link to core */
+		const char *show; /* The show child's cdata in a presence stanza */
+		const char *readable; /* readable representation */
+		JabberBuddyState state;
+} jabber_statuses[] = {
+	{ "offline",       NULL,   N_("Offline"),        JABBER_BUDDY_STATE_UNAVAILABLE },
+	{ "available",     NULL,   N_("Available"),      JABBER_BUDDY_STATE_ONLINE},
+	{ "freeforchat",   "chat", N_("Chatty"),         JABBER_BUDDY_STATE_CHAT },
+	{ "away",          "away", N_("Away"),           JABBER_BUDDY_STATE_AWAY },
+	{ "extended_away", "xa",   N_("Extended Away"),  JABBER_BUDDY_STATE_XA },
+	{ "dnd",           "dnd",  N_("Do Not Disturb"), JABBER_BUDDY_STATE_DND },
+	{ "error",         NULL,   N_("Error"),          JABBER_BUDDY_STATE_ERROR }
+};
+
+const char *
+jabber_buddy_state_get_name(const JabberBuddyState state)
+{
+	int i;
+	for (i = 0; i < G_N_ELEMENTS(jabber_statuses); ++i)
+		if (jabber_statuses[i].state == state)
+			return _(jabber_statuses[i].readable);
+
+	return _("Unknown");
+}
+
+JabberBuddyState
+jabber_buddy_status_id_get_state(const char *id)
+{
+	int i;
+	if (!id)
+		return JABBER_BUDDY_STATE_UNKNOWN;
+
+	for (i = 0; i < G_N_ELEMENTS(jabber_statuses); ++i)
+		if (g_str_equal(id, jabber_statuses[i].status_id))
+			return jabber_statuses[i].state;
+
+	return JABBER_BUDDY_STATE_UNKNOWN;
+}
+
+JabberBuddyState jabber_buddy_show_get_state(const char *id)
+{
+	int i;
+
+	g_return_val_if_fail(id != NULL, JABBER_BUDDY_STATE_UNKNOWN);
+
+	for (i = 0; i < G_N_ELEMENTS(jabber_statuses); ++i)
+		if (jabber_statuses[i].show && g_str_equal(id, jabber_statuses[i].show))
+			return jabber_statuses[i].state;
+
+	purple_debug_warning("jabber", "Invalid value of presence <show/> "
+	                     "attribute: %s\n", id);
+	return JABBER_BUDDY_STATE_UNKNOWN;
+}
+
+const char *
+jabber_buddy_state_get_show(JabberBuddyState state)
+{
+	int i;
+	for (i = 0; i < G_N_ELEMENTS(jabber_statuses); ++i)
+		if (state == jabber_statuses[i].state)
+			return jabber_statuses[i].show;
+
+	return NULL;
+}
+
+const char *
+jabber_buddy_state_get_status_id(JabberBuddyState state)
+{
+	int i;
+	for (i = 0; i < G_N_ELEMENTS(jabber_statuses); ++i)
+		if (state == jabber_statuses[i].state)
+			return jabber_statuses[i].status_id;
+
+	return NULL;
+}
+
 /* The same as purple_util_get_image_checksum, but guaranteed to remain SHA1 */
 char *
 jabber_calculate_data_sha1sum(gconstpointer data, size_t len)
--- a/libpurple/protocols/jabber/jutil.h	Tue Feb 16 08:38:20 2010 +0000
+++ b/libpurple/protocols/jabber/jutil.h	Tue Feb 16 15:16:28 2010 +0000
@@ -30,6 +30,17 @@
 	char *resource;
 } JabberID;
 
+typedef enum {
+	JABBER_BUDDY_STATE_UNKNOWN = -2,
+	JABBER_BUDDY_STATE_ERROR = -1,
+	JABBER_BUDDY_STATE_UNAVAILABLE = 0,
+	JABBER_BUDDY_STATE_ONLINE,
+	JABBER_BUDDY_STATE_CHAT,
+	JABBER_BUDDY_STATE_AWAY,
+	JABBER_BUDDY_STATE_XA,
+	JABBER_BUDDY_STATE_DND
+} JabberBuddyState;
+
 #include "jabber.h"
 
 JabberID* jabber_id_new(const char *str);
@@ -63,5 +74,16 @@
  */
 char *jabber_saslprep(const char *);
 
+/* state -> readable name */
+const char *jabber_buddy_state_get_name(JabberBuddyState state);
+/* state -> core id */
+const char *jabber_buddy_state_get_status_id(JabberBuddyState state);
+/* state -> show attr (for presence stanza) */
+const char *jabber_buddy_state_get_show(JabberBuddyState state);
+/* core id -> state */
+JabberBuddyState jabber_buddy_status_id_get_state(const char *id);
+/* show attr (presence stanza) -> state */
+JabberBuddyState jabber_buddy_show_get_state(const char *id);
+
 char *jabber_calculate_data_sha1sum(gconstpointer data, size_t len);
 #endif /* PURPLE_JABBER_JUTIL_H_ */