changeset 20641:707cd521188a

propagate from branch 'im.pidgin.pidgin' (head e67a54b3bf4349b6e65a46f749626a122c6afb22) to branch 'im.pidgin.sadrul.currentmedia' (head d3dc349e84591135f4f729a4e169ca65e48fc6e2)
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Fri, 21 Sep 2007 13:27:41 +0000
parents 485a0bffe4f5 (diff) ec11c8ec0305 (current diff)
children ba6cd9c25853
files libpurple/protocols/jabber/google.c pidgin/gtkblist.c
diffstat 15 files changed, 225 insertions(+), 153 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/jabber/google.c	Fri Sep 21 13:18:41 2007 +0000
+++ b/libpurple/protocols/jabber/google.c	Fri Sep 21 13:27:41 2007 +0000
@@ -513,3 +513,22 @@
 	}
 	return g_string_free(str, FALSE);
 }
+
+void jabber_google_presence_incoming(JabberStream *js, const char *user, JabberBuddyResource *jbr)
+{
+	if (!js->googletalk)
+		return;
+	if (jbr->status && !strncmp(jbr->status, "♫ ", strlen("♫ "))) {
+		purple_prpl_got_user_status(js->gc->account, user, "tune",
+					    PURPLE_TUNE_TITLE, jbr->status + strlen("♫ "), NULL);
+		jbr->status = NULL;
+	} else {
+		purple_prpl_got_user_status_deactive(js->gc->account, user, "tune");
+	}
+}
+
+char *jabber_google_presence_outgoing(PurpleStatus *tune)
+{
+	char *ret = g_strdup_printf("♫ %s", purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE));
+	return ret;
+}
--- a/libpurple/protocols/jabber/google.h	Fri Sep 21 13:18:41 2007 +0000
+++ b/libpurple/protocols/jabber/google.h	Fri Sep 21 13:27:41 2007 +0000
@@ -36,6 +36,10 @@
  * if this roster item should continue to be processed
  */
 gboolean jabber_google_roster_incoming(JabberStream *js, xmlnode *item);
+
+void jabber_google_presence_incoming(JabberStream *js, const char *who, JabberBuddyResource *jbr);
+char *jabber_google_presence_outgoing(PurpleStatus *tune);
+
 void jabber_google_roster_add_deny(PurpleConnection *gc, const char *who);
 void jabber_google_roster_rem_deny(PurpleConnection *gc, const char *who);
 
--- a/libpurple/protocols/jabber/jabber.c	Fri Sep 21 13:18:41 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Fri Sep 21 13:27:41 2007 +0000
@@ -1400,10 +1400,11 @@
 		char *stripped;
 
 		if(!(stripped = purple_markup_strip_html(jabber_buddy_get_status_msg(jb)))) {
-			PurpleStatus *status = purple_presence_get_active_status(purple_buddy_get_presence(b));
-
-			if(!purple_status_is_available(status))
-				stripped = g_strdup(purple_status_get_name(status));
+			PurplePresence *presence = purple_buddy_get_presence(b);
+			if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
+				PurpleStatus *status = purple_presence_get_status(presence, "tune");
+				stripped = g_strdup(purple_status_get_attr_string(status, PURPLE_TUNE_TITLE));
+			}
 		}
 
 		if(stripped) {
@@ -1429,6 +1430,7 @@
 
 	if(jb) {
 		JabberBuddyResource *jbr = NULL;
+		PurplePresence *presence = purple_buddy_get_presence(b);
 		const char *sub;
 		GList *l;
 		const char *mood;
@@ -1455,7 +1457,7 @@
 			
 			purple_notify_user_info_add_pair(user_info, _("Subscription"), sub);
 			
-			status = purple_presence_get_active_status(purple_buddy_get_presence(b));
+			status = purple_presence_get_active_status(presence);
 			value = purple_status_get_attr_value(status, "mood");
 			if (value && purple_value_get_type(value) == PURPLE_TYPE_STRING && (mood = purple_value_get_string(value))) {
 				
@@ -1467,7 +1469,12 @@
 					g_free(moodplustext);
 				} else
 					purple_notify_user_info_add_pair(user_info, _("Mood"), mood);
-		}
+			}
+			if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {	
+				PurpleStatus *tune = purple_presence_get_status(presence, "tune");
+				const char *title = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE);
+				purple_notify_user_info_add_pair(user_info, _("Current media"), title);
+			}
 		}
 
 		for(l=jb->resources; l; l = l->next) {
@@ -1532,15 +1539,6 @@
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
 			"mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
 			"moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
-			PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
-			PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
 			"nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
 			"buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN),
 			NULL);
@@ -1555,15 +1553,6 @@
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
 			"mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
 			"moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
-			PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
-			PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
 			"nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
 			"buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN),
 			NULL);
@@ -1578,15 +1567,6 @@
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
 			"mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
 			"moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
-			PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
-			PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
 			"nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
 			"buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN),
 			NULL);
@@ -1601,15 +1581,6 @@
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
 			"mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
 			"moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
-			PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
-			PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
 			"nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
 			"buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN),
 			NULL);
@@ -1624,15 +1595,6 @@
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
 			"mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING),
 			"moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
-			PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
-			PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
-			PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
 			"nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING),
 			"buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN),
 			NULL);
@@ -1650,6 +1612,20 @@
 			NULL);
 	types = g_list_append(types, type);
 
+	type = purple_status_type_new_with_attrs(PURPLE_STATUS_TUNE,
+			"tune", NULL, FALSE, FALSE, TRUE,
+			PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_GENRE, _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_COMMENT, _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TRACK, _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TIME, _("Tune Time"), purple_value_new(PURPLE_TYPE_INT),
+			PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT),
+			PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING),
+			NULL);
+	types = g_list_append(types, type);
+
 	return types;
 }
 
--- a/libpurple/protocols/jabber/message.c	Fri Sep 21 13:18:41 2007 +0000
+++ b/libpurple/protocols/jabber/message.c	Fri Sep 21 13:27:41 2007 +0000
@@ -104,6 +104,7 @@
 
 					g_snprintf(buf, sizeof(buf),
 					           _("%s has left the conversation."), escaped);
+					g_free(escaped);
 
 					/* At some point when we restructure PurpleConversation,
 					 * this should be able to be implemented by removing the
--- a/libpurple/protocols/jabber/presence.c	Fri Sep 21 13:18:41 2007 +0000
+++ b/libpurple/protocols/jabber/presence.c	Fri Sep 21 13:27:41 2007 +0000
@@ -33,6 +33,7 @@
 
 #include "buddy.h"
 #include "chat.h"
+#include "google.h"
 #include "presence.h"
 #include "iq.h"
 #include "jutil.h"
@@ -104,13 +105,14 @@
 	char *stripped = NULL;
 	JabberBuddyState state;
 	int priority;
-	const char *artist, *title, *source, *uri, *track;
-	int length;
+	const char *artist = NULL, *title = NULL, *source = NULL, *uri = NULL, *track = NULL;
+	int length = -1;
 	gboolean allowBuzz;
+	PurplePresence *p = purple_account_get_presence(account);
+	PurpleStatus *tune;
 
-	if(NULL == status) {
-		PurplePresence *gpresence = purple_account_get_presence(account);
-		status = purple_presence_get_active_status(gpresence);
+	if (NULL == status) {
+		status = purple_presence_get_active_status(p);
 	}
 
 	if(!purple_status_is_active(status))
@@ -144,6 +146,12 @@
 	if (allowBuzz != js->allowBuzz || js->old_state != state || CHANGED(js->old_msg, stripped) ||
 		js->old_priority != priority || CHANGED(js->old_avatarhash, js->avatar_hash)) {
 		js->allowBuzz = allowBuzz;
+
+		if (js->googletalk && stripped == NULL && purple_presence_is_status_primitive_active(p, PURPLE_STATUS_TUNE)) {
+			tune = purple_presence_get_status(p, "tune");
+			stripped = jabber_google_presence_outgoing(tune);
+		}
+
 		presence = jabber_presence_create_js(js, state, stripped, priority);
 
 		if(js->avatar_hash) {
@@ -172,12 +180,16 @@
 	}
 					  	
 	/* next, check if there are any changes to the tune values */
-	artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
-	title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
-	source = purple_status_get_attr_string(status, PURPLE_TUNE_ALBUM);
-	uri = purple_status_get_attr_string(status, PURPLE_TUNE_URL);
-	track = purple_status_get_attr_string(status, PURPLE_TUNE_TRACK);
-	length = (!purple_status_get_attr_value(status, PURPLE_TUNE_TIME))?-1:purple_status_get_attr_int(status, PURPLE_TUNE_TIME);
+	tune = purple_presence_get_status(p, "tune");
+	if (tune && purple_status_is_active(tune)) {
+		artist = purple_status_get_attr_string(tune, PURPLE_TUNE_ARTIST);
+		title = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE);
+		source = purple_status_get_attr_string(tune, PURPLE_TUNE_ALBUM);
+		uri = purple_status_get_attr_string(tune, PURPLE_TUNE_URL);
+		track = purple_status_get_attr_string(tune, PURPLE_TUNE_TRACK);
+		length = (!purple_status_get_attr_value(tune, PURPLE_TUNE_TIME)) ? -1 :
+				purple_status_get_attr_int(tune, PURPLE_TUNE_TIME);
+	}
 	
 	if(CHANGED(artist, js->old_artist) || CHANGED(title, js->old_title) || CHANGED(source, js->old_source) ||
 	   CHANGED(uri, js->old_uri) || CHANGED(track, js->old_track) || (length != js->old_length)) {
@@ -730,7 +742,8 @@
 		}
 
 		if((found_jbr = jabber_buddy_find_resource(jb, NULL))) {
-			purple_prpl_got_user_status(js->gc->account, buddy_name, jabber_buddy_state_get_status_id(found_jbr->state), "priority", found_jbr->priority, found_jbr->status ? "message" : NULL, found_jbr->status, NULL);
+			jabber_google_presence_incoming(js, buddy_name, found_jbr);
+			purple_prpl_got_user_status(js->gc->account, buddy_name, jabber_buddy_state_get_status_id(found_jbr->state), "priority", found_jbr->priority, "message", found_jbr->status, NULL);
 		} else {
 			purple_prpl_got_user_status(js->gc->account, buddy_name, "offline", status ? "message" : NULL, status, NULL);
 		}
--- a/libpurple/protocols/jabber/usertune.c	Fri Sep 21 13:18:41 2007 +0000
+++ b/libpurple/protocols/jabber/usertune.c	Fri Sep 21 13:27:41 2007 +0000
@@ -35,7 +35,6 @@
 	xmlnode *tuneinfo, *tune;
 	PurpleJabberTuneInfo tuneinfodata;
 	JabberBuddyResource *resource;
-	const char *status_id;
 	
 	/* ignore the tune of people not on our buddy list */
 	if (!buddy || !item)
@@ -81,9 +80,8 @@
 			}
 		}
 	}
-	status_id = jabber_buddy_state_get_status_id(resource->state);
 
-	purple_prpl_got_user_status(js->gc->account, from, status_id,
+	purple_prpl_got_user_status(js->gc->account, from, "tune",
 			PURPLE_TUNE_ARTIST, tuneinfodata.artist,
 			PURPLE_TUNE_TITLE, tuneinfodata.title,
 			PURPLE_TUNE_ALBUM, tuneinfodata.album,
--- a/libpurple/protocols/msn/msn.c	Fri Sep 21 13:18:41 2007 +0000
+++ b/libpurple/protocols/msn/msn.c	Fri Sep 21 13:27:41 2007 +0000
@@ -539,25 +539,36 @@
 
 /*
  * Set the User status text
- * Add the PSM String Using "Name - PSM String" format
  */
 static char *
 msn_status_text(PurpleBuddy *buddy)
 {
 	PurplePresence *presence;
 	PurpleStatus *status;
-	const char *msg, *cmedia;
+	const char *msg;
 
 	presence = purple_buddy_get_presence(buddy);
 	status = purple_presence_get_active_status(presence);
 
+	/* I think status message should take precedence over media */
 	msg = purple_status_get_attr_string(status, "message");
-	cmedia = purple_status_get_attr_string(status, "currentmedia");
-
-	if (cmedia)
-		return g_markup_escape_text(cmedia, -1);
-	else if (msg)
+	if (msg && *msg)
 		return g_markup_escape_text(msg, -1);
+
+	if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
+		const char *title, *artist;
+		char *media, *esc;
+		status = purple_presence_get_status(presence, "tune");
+		title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
+		artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
+
+		media = g_strdup_printf("%s%s%s", title, artist ? " - " : "",
+				artist ? artist : "");
+		esc = g_markup_escape_text(media, -1);
+		g_free(media);
+		return esc;
+	}
+
 	return NULL;
 }
 
@@ -570,14 +581,21 @@
 
 	user = buddy->proto_data;
 
-
 	if (purple_presence_is_online(presence))
 	{
-		const char *psm, *currentmedia, *name;
+		const char *psm, *name;
+		char *currentmedia = NULL;
 		char *tmp;
 
 		psm = purple_status_get_attr_string(status, "message");
-		currentmedia = purple_status_get_attr_string(status, "currentmedia");
+		if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
+			PurpleStatus *tune = purple_presence_get_status(presence, "tune");
+			const char *title = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE);
+			const char *artist = purple_status_get_attr_string(tune, PURPLE_TUNE_ARTIST);
+			currentmedia = g_strdup_printf("%s%s%s", title, artist ? " - " : "",
+					artist ? artist : "");
+			/* We could probably just use user->media.title etc. here */
+		}
 
 		if (!purple_presence_is_available(presence)) {
 			name = purple_status_get_name(status);
@@ -609,6 +627,7 @@
 			tmp = g_markup_escape_text(currentmedia, -1);
 			purple_notify_user_info_add_pair(user_info, _("Current media"), tmp);
 			g_free(tmp);
+			g_free(currentmedia);
 		}
 	}
 
@@ -632,40 +651,34 @@
 	status = purple_status_type_new_with_attrs(
 				PURPLE_STATUS_AVAILABLE, NULL, NULL, TRUE, TRUE, FALSE,
 				"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
-				"currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING),
 				NULL);
 	types = g_list_append(types, status);
 
 	status = purple_status_type_new_with_attrs(
 			PURPLE_STATUS_AWAY, NULL, NULL, TRUE, TRUE, FALSE,
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
-			"currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING),
 			NULL);
 	types = g_list_append(types, status);
 
 	status = purple_status_type_new_with_attrs(
 			PURPLE_STATUS_AWAY, "brb", _("Be Right Back"), TRUE, TRUE, FALSE,
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
-			"currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING),
 			NULL);
 	types = g_list_append(types, status);
 
 	status = purple_status_type_new_with_attrs(
 			PURPLE_STATUS_UNAVAILABLE, "busy", _("Busy"), TRUE, TRUE, FALSE,
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
-			"currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING),
 			NULL);
 	types = g_list_append(types, status);
 	status = purple_status_type_new_with_attrs(
 			PURPLE_STATUS_UNAVAILABLE, "phone", _("On the Phone"), TRUE, TRUE, FALSE,
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
-			"currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING),
 			NULL);
 	types = g_list_append(types, status);
 	status = purple_status_type_new_with_attrs(
 			PURPLE_STATUS_AWAY, "lunch", _("Out to Lunch"), TRUE, TRUE, FALSE,
 			"message", _("Message"), purple_value_new(PURPLE_TYPE_STRING),
-			"currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING),
 			NULL);
 	types = g_list_append(types, status);
 
@@ -681,6 +694,14 @@
 			"mobile", NULL, FALSE, FALSE, TRUE);
 	types = g_list_append(types, status);
 
+	status = purple_status_type_new_with_attrs(PURPLE_STATUS_TUNE,
+			"tune", NULL, FALSE, FALSE, TRUE,
+			PURPLE_TUNE_ARTIST, _("Artist"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_ALBUM, _("Album"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TITLE, _("Title"), purple_value_new(PURPLE_TYPE_STRING),
+			NULL);
+	types = g_list_append(types, status);
+
 	return types;
 }
 
--- a/libpurple/protocols/msn/notification.c	Fri Sep 21 13:18:41 2007 +0000
+++ b/libpurple/protocols/msn/notification.c	Fri Sep 21 13:27:41 2007 +0000
@@ -1625,10 +1625,8 @@
 	PurpleConnection *gc;
 	MsnUser *user;
 	const char *passport;
-	char *psm_str, *currentmedia_str, *str;
-
-	/*get the payload content*/
-//	purple_debug_info("MSNP14","UBX {%s} payload{%s}\n",cmd->params[0], cmd->payload);
+	char *psm_str, *str;
+	CurrentMedia media = {NULL, NULL, NULL};
 
 	session = cmdproc->session;
 	account = session->account;
@@ -1638,16 +1636,17 @@
 	user = msn_userlist_find_user(session->userlist, passport);
 	
 	psm_str = msn_get_psm(cmd->payload,len);
-	currentmedia_str = msn_parse_currentmedia(
-	                                 str = msn_get_currentmedia(cmd->payload, len));
+	msn_user_set_statusline(user, psm_str);
+	g_free(psm_str);
+
+	str = msn_get_currentmedia(cmd->payload, len);
+	if (msn_parse_currentmedia(str, &media))
+		msn_user_set_currentmedia(user, &media);
+	else
+		msn_user_set_currentmedia(user, NULL);
 	g_free(str);
 
-	msn_user_set_statusline(user, psm_str);
-	msn_user_set_currentmedia(user, currentmedia_str);
 	msn_user_update(user);
-
-	g_free(psm_str);
-	g_free(currentmedia_str);
 }
 
 static void
--- a/libpurple/protocols/msn/state.c	Fri Sep 21 13:18:41 2007 +0000
+++ b/libpurple/protocols/msn/state.c	Fri Sep 21 13:27:41 2007 +0000
@@ -83,60 +83,56 @@
 }
 
 /* parse CurrentMedia string */
-char *
-msn_parse_currentmedia(const char *cmedia)
+gboolean
+msn_parse_currentmedia(const char *cmedia, CurrentMedia *media)
 {
 	char **cmedia_array;
-	GString *buffer = NULL;
 	int strings;
 
 	if ((cmedia == NULL) || (*cmedia == '\0')) {
 		purple_debug_info("msn", "No currentmedia string\n");
-		return NULL;
+		return FALSE;
 	}
 
 	purple_debug_info("msn", "Parsing currentmedia string: \"%s\"\n", cmedia);
 
 	cmedia_array = g_strsplit(cmedia, "\\0", 0);
 
+	/*
+	 * 0: Media Player
+	 * 1: 'Music'
+	 * 2: '1' if enabled, '0' if not
+	 * 3: Format (eg. {0} by {1})
+	 * 4: Title
+	 * 5: Artist
+	 * 6: Album
+	 * 7: ?
+	 */
 	strings = 0;
-	/* Yes, we want to skip the first element here, as it is empty due to
-	 * the cmedia string starting with \0 -- see the examples below. */
 	while (cmedia_array[++strings] != NULL);
 
-	/* The cmedia_array[2] field contains a 1 if enabled. */
-	if ((strings > 3) && (!strcmp(cmedia_array[2], "1"))) {
-		char *inptr = cmedia_array[3];
-
-		buffer = g_string_new(NULL);
-
-		while (*inptr != '\0') {
-			if ((*inptr == '{') && ((*(inptr + 1) != '\0') && (*(inptr+2) == '}'))) {
-				char *tmpptr;
-				int tmp;
-
-				errno = 0;
-				tmp = strtol(inptr + 1, &tmpptr, 10);
+	if (strings < 4)
+		return FALSE;
+	if (strcmp(cmedia_array[2], "1"))
+		return FALSE;
 
-				if (errno == 0 && tmpptr != inptr + 1 &&
-				    tmp + 4 < strings) {
-					/* Replace {?} tag with appropriate text only when successful.
-					 * Skip otherwise. */
-					buffer = g_string_append(buffer, cmedia_array[tmp + 4]);
-				}
-				inptr += 3; /* Skip to the next char after '}' */
-			} else {
-				buffer = g_string_append_c(buffer, *inptr++);
-			}
-		}
-		purple_debug_info("msn", "Parsed currentmedia string, result: \"%s\"\n",
-		                  buffer->str);
+	if (strings == 4) {
+		media->title = g_strdup(cmedia_array[3]);
 	} else {
-		purple_debug_info("msn", "Current media marked disabled, not parsing.\n");
+		media->title = g_strdup(cmedia_array[4]);
 	}
 
-	g_strfreev(cmedia_array);
-	return buffer ? g_string_free(buffer, FALSE) : NULL;
+	if (strings > 5)
+		media->artist = g_strdup(cmedia_array[5]);
+	else
+		media->artist = NULL;
+
+	if (strings > 6)
+		media->album = g_strdup(cmedia_array[6]);
+	else
+		media->album = NULL;
+
+	return TRUE;
 }
 
 /* get the CurrentMedia info from the XML string */
@@ -191,6 +187,27 @@
 	return psm;
 }
 
+static char *
+create_media_string(PurplePresence *presence)
+{
+	const char *artist, *title, *album;
+	char *ret;
+	PurpleStatus *status = purple_presence_get_status(presence, "tune");
+	if (!status || !purple_status_is_active(status))
+		return g_strdup_printf("WMP\\0Music\\00\\0{0} - {1}\\0\\0\\0\\0\\0");
+
+	artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
+	title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
+	album = purple_status_get_attr_string(status, PURPLE_TUNE_ALBUM);
+
+	ret = g_strdup_printf("WMP\\0Music\\0%c\\0{0} - {1}\\0%s\\0%s\\0%s\\0\\0",
+			(title && *title) ? '1' : '0',
+			title ? title : "",
+			artist ? artist : "",
+			album ? album : "");
+	return ret;
+}
+
 /* set the MSN's PSM info,Currently Read from the status Line 
  * Thanks for Cris Code
  */
@@ -204,7 +221,7 @@
 	MsnTransaction *trans;
 	char *payload;
 	const char *statusline;
-	gchar *unescapedstatusline;
+	gchar *unescapedstatusline, *media = NULL;
 
 	g_return_if_fail(session != NULL);
 	g_return_if_fail(session->notification != NULL);
@@ -219,8 +236,10 @@
 	status = purple_presence_get_active_status(presence);
 	statusline = purple_status_get_attr_string(status, "message");
 	unescapedstatusline = purple_unescape_html(statusline);
-	session->psm = msn_build_psm(unescapedstatusline, NULL, NULL);
+	media = create_media_string(presence);
+	session->psm = msn_build_psm(unescapedstatusline, media, NULL);
 	g_free(unescapedstatusline);
+	g_free(media);
 	payload = session->psm;
 
 	purple_debug_misc("MSNP14","Sending UUX command with payload: %s\n",payload);
--- a/libpurple/protocols/msn/state.h	Fri Sep 21 13:18:41 2007 +0000
+++ b/libpurple/protocols/msn/state.h	Fri Sep 21 13:27:41 2007 +0000
@@ -62,7 +62,7 @@
 void msn_set_psm(MsnSession *session);
 
 /* Parse CurrentMedia string */
-char * msn_parse_currentmedia(const char *cmedia);
+gboolean msn_parse_currentmedia(const char *cmedia, CurrentMedia *media);
 
 /* Get the CurrentMedia info from the XML string */
 char * msn_get_currentmedia(char *xml_str,gsize len);
--- a/libpurple/protocols/msn/user.c	Fri Sep 21 13:18:41 2007 +0000
+++ b/libpurple/protocols/msn/user.c	Fri Sep 21 13:27:41 2007 +0000
@@ -80,6 +80,9 @@
 	g_free(user->phone.home);
 	g_free(user->phone.work);
 	g_free(user->phone.mobile);
+	g_free(user->media.artist);
+	g_free(user->media.title);
+	g_free(user->media.album);
 
 	g_free(user);
 }
@@ -91,23 +94,24 @@
 
 	account = user->userlist->session->account;
 
-	if (user->statusline != NULL && user->currentmedia != NULL) {
+	if (user->status != NULL) {
+		gboolean offline = (strcmp(user->status, "offline") == 0);
 		purple_prpl_got_user_status(account, user->passport, user->status,
-		                          "message", user->statusline,
-		                          "currentmedia", user->currentmedia, NULL);
-	} else if (user->currentmedia != NULL) {
-		purple_prpl_got_user_status(account, user->passport, user->status, "currentmedia",
-		                          user->currentmedia, NULL);
-	} else if (user->statusline != NULL) {
-		//char *status = g_strdup_printf("%s - %s", user->status, user->statusline);
-		purple_prpl_got_user_status(account, user->passport, user->status,
-		                          "message", user->statusline, NULL);
-	} else if (user->status != NULL) {
-		if (!strcmp(user->status, "offline") && user->mobile) {
-			purple_prpl_got_user_status(account, user->passport, "offline", NULL);
+				"message", user->statusline, NULL);
+
+		if (!offline && user->media.title) {
+			purple_prpl_got_user_status(account, user->passport, "tune",
+					PURPLE_TUNE_ARTIST, user->media.artist,
+					PURPLE_TUNE_ALBUM, user->media.album,
+					PURPLE_TUNE_TITLE, user->media.title,
+					NULL);
+		} else {
+			purple_prpl_got_user_status_deactive(account, user->passport, "tune");
+		}
+
+		if (!offline && user->mobile) {
 			purple_prpl_got_user_status(account, user->passport, "mobile", NULL);
 		} else {
-			purple_prpl_got_user_status(account, user->passport, user->status, NULL);
 			purple_prpl_got_user_status_deactive(account, user->passport, "mobile");
 		}
 	}
@@ -172,12 +176,17 @@
 }
 
 void
-msn_user_set_currentmedia(MsnUser *user, const char *currentmedia)
+msn_user_set_currentmedia(MsnUser *user, const CurrentMedia *media)
 {
 	g_return_if_fail(user != NULL);
 
-	g_free(user->currentmedia);
-	user->currentmedia = g_strdup(currentmedia);
+	g_free(user->media.title);
+	g_free(user->media.album);
+	g_free(user->media.artist);
+
+	user->media.title  = media ? g_strdup(media->title) : NULL;
+	user->media.artist = media ? g_strdup(media->artist) : NULL;
+	user->media.album  = media ? g_strdup(media->album) : NULL;
 }
 
 void
--- a/libpurple/protocols/msn/user.h	Fri Sep 21 13:18:41 2007 +0000
+++ b/libpurple/protocols/msn/user.h	Fri Sep 21 13:27:41 2007 +0000
@@ -43,6 +43,16 @@
 } MsnUserType;
 
 /**
+ * Current media.
+ */
+typedef struct _CurrentMedia
+{
+	char *artist;   /**< Artist. */
+	char *album;    /**< Album.  */
+	char *title;    /**< Title.  */
+} CurrentMedia;
+
+/**
  * A user.
  */
 struct _MsnUser
@@ -60,7 +70,7 @@
 
 	const char *status;     /**< The state of the user.         */
 	char *statusline;       /**< The state of the user.         */	
-	char *currentmedia;     /**< The current media of the user. */
+	CurrentMedia media;     /**< Current media of the user.     */
 
 	gboolean idle;          /**< The idle state of the user.    */
 
@@ -134,10 +144,10 @@
  /**
   *  Sets the current media of user.
   * 
-  *  @param user The user.
-  *  @param state The statusline string.
+  *  @param user   The user.
+  *  @param cmedia Current media.
   */
-void msn_user_set_currentmedia(MsnUser *user, const char *currentmedia);
+void msn_user_set_currentmedia(MsnUser *user, const CurrentMedia *cmedia);
 
 /**
  * Sets the new state of user.
--- a/libpurple/status.c	Fri Sep 21 13:18:41 2007 +0000
+++ b/libpurple/status.c	Fri Sep 21 13:27:41 2007 +0000
@@ -903,6 +903,8 @@
 	}
 	g_return_if_fail(purple_value_get_type(attr_value) == PURPLE_TYPE_STRING);
 
+	/* XXX: Check if the value has actually changed. If it has, and the status
+	 * is active, should this trigger 'status_has_changed'? */
 	purple_value_set_string(attr_value, value);
 }
 
--- a/libpurple/status.h	Fri Sep 21 13:18:41 2007 +0000
+++ b/libpurple/status.h	Fri Sep 21 13:27:41 2007 +0000
@@ -104,6 +104,7 @@
 	PURPLE_STATUS_AWAY,
 	PURPLE_STATUS_EXTENDED_AWAY,
 	PURPLE_STATUS_MOBILE,
+	PURPLE_STATUS_TUNE,
 	PURPLE_STATUS_NUM_PRIMITIVES
 
 } PurpleStatusPrimitive;
--- a/pidgin/gtkblist.c	Fri Sep 21 13:18:41 2007 +0000
+++ b/pidgin/gtkblist.c	Fri Sep 21 13:27:41 2007 +0000
@@ -3384,7 +3384,7 @@
 		return ret;
 	}
 
-	if (purple_status_get_attr_string(purple_presence_get_active_status(p), PURPLE_TUNE_TITLE)) {
+	if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_TUNE)) {
 		path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "music.png", NULL);
 		ret = gdk_pixbuf_new_from_file(path, NULL);
 		g_free(path);