# HG changeset patch # User Nathan Walp # Date 1146446538 0 # Node ID 3eb7a5f0de8243d2d52d356f759447de0b8290e7 # Parent 2f7b356812bcbb7e6992ad7d68a1e22f9db8473c [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 diff -r 2f7b356812bc -r 3eb7a5f0de82 src/protocols/jabber/buddy.h --- 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); diff -r 2f7b356812bc -r 3eb7a5f0de82 src/protocols/jabber/message.c --- 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("%s", 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; } diff -r 2f7b356812bc -r 3eb7a5f0de82 src/protocols/jabber/message.h --- 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;