# HG changeset patch # User Mikael Berthe # Date 1162339076 -3600 # Node ID 35e7913affb73cf5c9d3d09f24bca00138544552 # Parent 859ab76e5093611db55ca24febdd32d0c68d0b68 Send events/chatstates notifications (JEP-22/JEP-85) diff -r 859ab76e5093 -r 35e7913affb7 mcabber/src/jabglue.c --- a/mcabber/src/jabglue.c Tue Oct 31 20:30:29 2006 +0100 +++ b/mcabber/src/jabglue.c Wed Nov 01 00:57:56 2006 +0100 @@ -481,6 +481,7 @@ jep85->support = CHATSTATES_SUPPORT_PROBED; else which_jep = 1; + jep85->last_state_sent = ROSTER_EVENT_ACTIVE; } #endif #ifdef JEP0022 @@ -489,19 +490,22 @@ * If not, we try to fall back to JEP-0022. */ if (!which_jep) { + struct jep0022 *jep22 = NULL; event = xmlnode_insert_tag(x, "x"); xmlnode_put_attrib(event, "xmlns", NS_EVENT); xmlnode_insert_tag(event, "composing"); + if (sl_buddy) + jep22 = buddy_resource_jep22(sl_buddy->data, rname); + if (jep22) + jep22->last_state_sent = ROSTER_EVENT_ACTIVE; + // An id is mandatory when using JEP-0022. if (!msgid && (text || subject)) { - struct jep0022 *jep22; msgid = new_msgid(); // Let's update last_msgid_sent // (We do not update it when the msgid is provided by the caller, // because this is probably a special message...) - if (sl_buddy) - jep22 = buddy_resource_jep22(sl_buddy->data, rname); if (jep22) { g_free(jep22->last_msgid_sent); jep22->last_msgid_sent = g_strdup(msgid); @@ -518,10 +522,68 @@ jb_reset_keepalive(); } + +#ifdef JEP0085 +// jb_send_jep85_chatstate() +// Send a JEP-85 chatstate. +static void jb_send_jep85_chatstate(const char *jid, guint state) +{ + xmlnode x; + xmlnode event; + char *rname, *barejid; + GSList *sl_buddy; + const char *chattag; + struct jep0085 *jep85 = NULL; + + if (!online) return; + + rname = strchr(jid, JID_RESOURCE_SEPARATOR); + barejid = jidtodisp(jid); + sl_buddy = roster_find(barejid, jidsearch, ROSTER_TYPE_USER); + g_free(barejid); + + // If we can get a resource name, we use it. Else we use NULL, + // which hopefully will give us the most likely resource. + if (rname) + rname++; + if (sl_buddy) + jep85 = buddy_resource_jep85(sl_buddy->data, rname); + + if (!jep85 || (jep85->support != CHATSTATES_SUPPORT_OK)) + return; + + if (state == jep85->last_state_sent) + return; + + if (state == ROSTER_EVENT_ACTIVE) + chattag = "active"; + else if (state == ROSTER_EVENT_COMPOSING) + chattag = "composing"; + else if (state == ROSTER_EVENT_PAUSED) + chattag = "paused"; + else { + scr_LogPrint(LPRINT_LOGNORM, "Error: unsupported JEP-85 state (%d)", state); + return; + } + + jep85->last_state_sent = state; + + x = jutil_msgnew(TMSG_CHAT, (char*)jid, NULL, NULL); + + event = xmlnode_insert_tag(x, chattag); + xmlnode_put_attrib(event, "xmlns", NS_CHATSTATES); + + jab_send(jc, x); + xmlnode_free(x); + + jb_reset_keepalive(); +} +#endif + #ifdef JEP0022 // jb_send_jep22_event() // Send a JEP-22 message event (delivered, composing...). -void jb_send_jep22_event(const char *jid, guint type) +static void jb_send_jep22_event(const char *jid, guint type) { xmlnode x; xmlnode event; @@ -529,6 +591,7 @@ char *rname, *barejid; GSList *sl_buddy; struct jep0022 *jep22 = NULL; + guint jep22_state; if (!online) return; @@ -544,8 +607,27 @@ if (sl_buddy) jep22 = buddy_resource_jep22(sl_buddy->data, rname); - if (jep22) - msgid = jep22->last_msgid_rcvd; + if (!jep22) + return; // XXX Maybe we could try harder (other resources?) + + msgid = jep22->last_msgid_rcvd; + + // For composing events (composing, active, inactive, paused...), + // JEP22 only has 2 states; we'll use composing and active. + if (type == ROSTER_EVENT_COMPOSING) + jep22_state = ROSTER_EVENT_COMPOSING; + else if (type == ROSTER_EVENT_ACTIVE || + type == ROSTER_EVENT_PAUSED) + jep22_state = ROSTER_EVENT_ACTIVE; + else + jep22_state = 0; // ROSTER_EVENT_NONE + + if (jep22_state) { + // Do not re-send a same event + if (jep22_state == jep22->last_state_sent) + return; + jep22->last_state_sent = jep22_state; + } x = jutil_msgnew(TMSG_CHAT, (char*)jid, NULL, NULL); @@ -555,7 +637,7 @@ xmlnode_insert_tag(event, "delivered"); else if (type == ROSTER_EVENT_COMPOSING) xmlnode_insert_tag(event, "composing"); - xmlnode_put_attrib(event, "id", (msgid ? msgid : "")); + xmlnode_put_attrib(event, "id", msgid); jab_send(jc, x); xmlnode_free(x); @@ -564,6 +646,34 @@ } #endif +#if defined JEP0022 || defined JEP0085 +void jb_send_chatstate(gpointer buddy, guint chatstate) +{ + const char *jid; + struct jep0085 *jep85 = NULL; + struct jep0022 *jep22 = NULL; + + jid = buddy_getjid(buddy); + if (!jid) return; + +#ifdef JEP0085 + jep85 = buddy_resource_jep85(buddy, NULL); + if (jep85 && jep85->support == CHATSTATES_SUPPORT_OK) { + // FIXME: compare w/ last state sent... + jb_send_jep85_chatstate(jid, chatstate); + return; + } +#endif +#ifdef JEP0022 + jep22 = buddy_resource_jep22(buddy, NULL); + if (jep22 && jep22->support == CHATSTATES_SUPPORT_OK) { + // FIXME: compare w/ last state sent... + jb_send_jep22_event(jid, chatstate); + } +#endif +} +#endif + // jb_subscr_send_auth(jid) // Allow jid to receive our presence updates void jb_subscr_send_auth(const char *jid) @@ -1572,14 +1682,14 @@ void handle_state_events(char *from, xmlnode xmldata) { #if defined JEP0022 || defined JEP0085 - xmlnode state_ns; + xmlnode state_ns = NULL; const char *body; char *rname, *jid; GSList *sl_buddy; guint events; guint which_jep = 0; /* 0: none, 1: 85, 2: 22 */ - struct jep0022 *jep22; - struct jep0085 *jep85; + struct jep0022 *jep22 = NULL; + struct jep0085 *jep85 = NULL; rname = strchr(from, JID_RESOURCE_SEPARATOR); jid = jidtodisp(from); diff -r 859ab76e5093 -r 35e7913affb7 mcabber/src/jabglue.h --- a/mcabber/src/jabglue.h Tue Oct 31 20:30:29 2006 +0100 +++ b/mcabber/src/jabglue.h Wed Nov 01 00:57:56 2006 +0100 @@ -52,6 +52,7 @@ void jb_send_msg(const char *jid, const char *text, int type, const char *subject, const char *id); void jb_send_raw(const char *str); +void jb_send_chatstate(gpointer buddy, guint chatstate); void jb_keepalive(void); inline void jb_reset_keepalive(void); void jb_set_keepalive_delay(unsigned int delay); diff -r 859ab76e5093 -r 35e7913affb7 mcabber/src/screen.c --- a/mcabber/src/screen.c Tue Oct 31 20:30:29 2006 +0100 +++ b/mcabber/src/screen.c Wed Nov 01 00:57:56 2006 +0100 @@ -95,6 +95,9 @@ static GList *cmdhisto_cur; static char cmdhisto_backup[INPUTLINE_LENGTH+1]; +static int chatstate; +static bool lock_chatstate; + #define MAX_KEYSEQ_LENGTH 8 typedef struct { @@ -1408,6 +1411,30 @@ } } +// set_chatstate(state) +// Set the current chat state (0=active, 1=composing, 2=paused) +static inline void set_chatstate(int state) +{ +#if defined JEP0022 || defined JEP0085 + if (!chatmode) + state = 0; + if (state != chatstate) { + chatstate = state; + if (current_buddy && + buddy_gettype(BUDDATA(current_buddy)) == ROSTER_TYPE_USER) { + guint jep_state; + if (chatstate == 1) + jep_state = ROSTER_EVENT_COMPOSING; + else if (chatstate == 2) + jep_state = ROSTER_EVENT_PAUSED; + else + jep_state = ROSTER_EVENT_ACTIVE; + jb_send_chatstate(BUDDATA(current_buddy), jep_state); + } + } +#endif +} + // set_current_buddy(newbuddy) // Set the current_buddy to newbuddy (if not NULL) // Lock the newbuddy, and unlock the previous current_buddy @@ -1422,6 +1449,11 @@ if (!current_buddy || !newbuddy) return; if (newbuddy == current_buddy) return; + // We're moving to another buddy. We're thus inactive wrt current_buddy. + set_chatstate(0); + // We don't want the chatstate to be changed again right now. + lock_chatstate = true; + prev_st = buddy_getstatus(BUDDATA(current_buddy), NULL); buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE); if (chatmode) @@ -2530,6 +2562,8 @@ int key = kcode.value; int display_char = FALSE; + lock_chatstate = false; + switch (kcode.mcode) { case 0: break; @@ -2753,6 +2787,13 @@ if (completion_started && key != 9 && key != KEY_RESIZE) scr_end_current_completion(); refresh_inputline(); + + if (!lock_chatstate) { + if (inputLine[0] == 0 || inputLine[0] == COMMAND_CHAR) + set_chatstate(0); + else + set_chatstate(1); + } return 0; }