changeset 13706:3eb7a5f0de82

[gaim-migrate @ 16110] support for JEP-0085 (chat state notifications) Basically, this gains us the ability to send/receive the fact that a user has typed, and then stopped. This has passed the WorksForMe(TM) test suite...lemme know if you notice anything weird. committer: Tailor Script <tailor@pidgin.im>
author Nathan Walp <nwalp@pidgin.im>
date Mon, 01 May 2006 01:22:18 +0000
parents 2f7b356812bc
children 1e6de7b949d4
files src/protocols/jabber/buddy.h src/protocols/jabber/message.c src/protocols/jabber/message.h
diffstat 3 files changed, 114 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/jabber/buddy.h	Sat Apr 29 20:47:20 2006 +0000
+++ b/src/protocols/jabber/buddy.h	Mon May 01 01:22:18 2006 +0000
@@ -61,6 +61,16 @@
 	char *status;
 	JabberCapabilities capabilities;
 	char *thread_id;
+	enum {
+		JABBER_CHAT_STATES_UNKNOWN,
+		JABBER_CHAT_STATES_UNSUPPORTED,
+		JABBER_CHAT_STATES_SUPPORTED
+	} chat_states;
+	struct {
+		char *version;
+		char *name;
+		char *os;
+	} client;
 } JabberBuddyResource;
 
 void jabber_buddy_free(JabberBuddy *jb);
--- a/src/protocols/jabber/message.c	Sat Apr 29 20:47:20 2006 +0000
+++ b/src/protocols/jabber/message.c	Mon May 01 01:22:18 2006 +0000
@@ -30,8 +30,6 @@
 #include "message.h"
 #include "xmlnode.h"
 
-#define JABBER_TYPING_NOTIFY_INT 15
-
 void jabber_message_free(JabberMessage *jm)
 {
         g_free(jm->from);
@@ -79,14 +77,24 @@
 	}
 
 	if(!jm->xhtml && !jm->body) {
-		if(jm->events & JABBER_MESSAGE_EVENT_COMPOSING)
+		if(JM_STATE_COMPOSING == jm->chat_state)
 			serv_got_typing(jm->js->gc, from, 0, GAIM_TYPING);
+		else if(JM_STATE_PAUSED == jm->chat_state)
+			serv_got_typing(jm->js->gc, from, 0, GAIM_TYPED);
 		else
 			serv_got_typing_stopped(jm->js->gc, from);
 	} else {
 		if(jbr) {
-			if(jm->events & JABBER_MESSAGE_EVENT_COMPOSING)
+			if(JM_TS_JEP_0085 == (jm->typing_style & JM_TS_JEP_0085)) {
+				jbr->chat_states = JABBER_CHAT_STATES_SUPPORTED;
+			} else {
+				jbr->chat_states = JABBER_CHAT_STATES_UNSUPPORTED;
+			}
+
+			if(JM_TS_JEP_0022 == (jm->typing_style & JM_TS_JEP_0022)) {
 				jbr->capabilities |= JABBER_CAP_COMPOSING;
+			}
+
 			if(jbr->thread_id)
 				g_free(jbr->thread_id);
 			jbr->thread_id = g_strdup(jbr->thread_id);
@@ -95,6 +103,7 @@
 				jm->sent);
 	}
 
+
 	g_free(from);
 	jabber_id_free(jid);
 }
@@ -286,6 +295,21 @@
 		} else if(!strcmp(child->name, "html")) {
 			if(!jm->xhtml && xmlnode_get_child(child, "body"))
 				jm->xhtml = xmlnode_to_str(child, NULL);
+		} else if(!strcmp(child->name, "active")) {
+			jm->chat_state = JM_STATE_ACTIVE;
+			jm->typing_style |= JM_TS_JEP_0085;
+		} else if(!strcmp(child->name, "composing")) {
+			jm->chat_state = JM_STATE_COMPOSING;
+			jm->typing_style |= JM_TS_JEP_0085;
+		} else if(!strcmp(child->name, "paused")) {
+			jm->chat_state = JM_STATE_PAUSED;
+			jm->typing_style |= JM_TS_JEP_0085;
+		} else if(!strcmp(child->name, "inactive")) {
+			jm->chat_state = JM_STATE_INACTIVE;
+			jm->typing_style |= JM_TS_JEP_0085;
+		} else if(!strcmp(child->name, "gone")) {
+			jm->chat_state = JM_STATE_GONE;
+			jm->typing_style |= JM_TS_JEP_0085;
 		} else if(!strcmp(child->name, "error")) {
 			const char *code = xmlnode_get_attrib(child, "code");
 			char *code_txt = NULL;
@@ -303,8 +327,11 @@
 		} else if(!strcmp(child->name, "x")) {
 			const char *xmlns = xmlnode_get_attrib(child, "xmlns");
 			if(xmlns && !strcmp(xmlns, "jabber:x:event")) {
-				if(xmlnode_get_child(child, "composing"))
-					jm->events |= JABBER_MESSAGE_EVENT_COMPOSING;
+				if(xmlnode_get_child(child, "composing")) {
+					if(jm->chat_state == JM_STATE_ACTIVE)
+						jm->chat_state = JM_STATE_COMPOSING;
+					jm->typing_style |= JM_TS_JEP_0022;
+				}
 			} else if(xmlns && !strcmp(xmlns, "jabber:x:delay")) {
 				const char *timestamp = xmlnode_get_attrib(child, "stamp");
 				jm->delayed = TRUE;
@@ -411,13 +438,37 @@
 		xmlnode_insert_data(child, jm->thread_id, -1);
 	}
 
-	if(jm->events || (!jm->body && !jm->xhtml && !jm->subject)) {
+	if(JM_TS_JEP_0022 == (jm->typing_style & JM_TS_JEP_0022)) {
 		child = xmlnode_new_child(message, "x");
 		xmlnode_set_attrib(child, "xmlns", "jabber:x:event");
-		if(jm->events & JABBER_MESSAGE_EVENT_COMPOSING)
+		if(jm->chat_state == JM_STATE_COMPOSING || jm->body)
 			xmlnode_new_child(child, "composing");
 	}
 
+	if(JM_TS_JEP_0085 == (jm->typing_style & JM_TS_JEP_0085)) {
+		child = NULL;
+		switch(jm->chat_state)
+		{
+			case JM_STATE_ACTIVE:
+				child = xmlnode_new_child(message, "active");
+				break;
+			case JM_STATE_COMPOSING:
+				child = xmlnode_new_child(message, "composing");
+				break;
+			case JM_STATE_PAUSED:
+				child = xmlnode_new_child(message, "paused");
+				break;
+			case JM_STATE_INACTIVE:
+				child = xmlnode_new_child(message, "inactive");
+				break;
+			case JM_STATE_GONE:
+				child = xmlnode_new_child(message, "gone");
+				break;
+		}
+		if(child)
+			xmlnode_set_attrib(child, "xmlns", "http://jabber.org/protocol/chatstates");
+	}
+
 	if(jm->subject) {
 		child = xmlnode_new_child(message, "subject");
 		xmlnode_insert_data(child, jm->subject, -1);
@@ -467,11 +518,24 @@
 	jm = g_new0(JabberMessage, 1);
 	jm->js = gc->proto_data;
 	jm->type = JABBER_MESSAGE_CHAT;
-	jm->events = JABBER_MESSAGE_EVENT_COMPOSING;
+	jm->chat_state = JM_STATE_ACTIVE;
 	jm->to = g_strdup(who);
 	jm->id = jabber_get_next_id(jm->js);
-	if(jbr && jbr->thread_id)
-		jm->thread_id = jbr->thread_id;
+	jm->chat_state = JM_STATE_ACTIVE;
+
+	if(jbr) {
+		if(jbr->thread_id)
+			jm->thread_id = jbr->thread_id;
+
+		if(jbr->chat_states != JABBER_CHAT_STATES_UNSUPPORTED) {
+			jm->typing_style |= JM_TS_JEP_0085;
+			/* if(JABBER_CHAT_STATES_UNKNOWN == jbr->chat_states)
+			   jbr->chat_states = JABBER_CHAT_STATES_UNSUPPORTED; */
+		}
+
+		if(jbr->chat_states != JABBER_CHAT_STATES_SUPPORTED)
+			jm->typing_style |= JM_TS_JEP_0022;
+	}
 
 	buf = g_strdup_printf("<html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'>%s</body></html>", msg);
 
@@ -537,21 +601,35 @@
 
 	g_free(resource);
 
-	if(!jbr || !(jbr->capabilities & JABBER_CAP_COMPOSING))
+	if(!jbr || !((jbr->capabilities & JABBER_CAP_COMPOSING) || (jbr->chat_states != JABBER_CHAT_STATES_UNSUPPORTED)))
 		return 0;
 
+	/* TODO: figure out threading */
 	jm = g_new0(JabberMessage, 1);
 	jm->js = gc->proto_data;
 	jm->type = JABBER_MESSAGE_CHAT;
 	jm->to = g_strdup(who);
 	jm->id = jabber_get_next_id(jm->js);
 
-	if(typing == GAIM_TYPING)
-		jm->events = JABBER_MESSAGE_EVENT_COMPOSING;
+	if(GAIM_TYPING == typing)
+		jm->chat_state = JM_STATE_COMPOSING;
+	else if(GAIM_TYPED == typing)
+		jm->chat_state = JM_STATE_PAUSED;
+	else
+		jm->chat_state = JM_STATE_ACTIVE;
+
+	if(jbr->chat_states != JABBER_CHAT_STATES_UNSUPPORTED) {
+		jm->typing_style |= JM_TS_JEP_0085;
+		/* if(JABBER_CHAT_STATES_UNKNOWN == jbr->chat_states)
+			jbr->chat_states = JABBER_CHAT_STATES_UNSUPPORTED; */
+	}
+
+	if(jbr->chat_states != JABBER_CHAT_STATES_SUPPORTED)
+		jm->typing_style |= JM_TS_JEP_0022;
 
 	jabber_message_send(jm);
 	jabber_message_free(jm);
 
-	return JABBER_TYPING_NOTIFY_INT;
+	return 0;
 }
 
--- a/src/protocols/jabber/message.h	Sat Apr 29 20:47:20 2006 +0000
+++ b/src/protocols/jabber/message.h	Mon May 01 01:22:18 2006 +0000
@@ -48,8 +48,17 @@
 	char *error;
 	char *thread_id;
 	enum {
-		JABBER_MESSAGE_EVENT_COMPOSING = 1 << 1
-	} events;
+		JM_TS_NONE = 0,
+		JM_TS_JEP_0022 = 0x1,
+		JM_TS_JEP_0085 = 0x2
+	} typing_style;
+	enum {
+		JM_STATE_ACTIVE,
+		JM_STATE_COMPOSING,
+		JM_STATE_PAUSED,
+		JM_STATE_INACTIVE,
+		JM_STATE_GONE
+	} chat_state;
 	GList *etc;
 } JabberMessage;