--- 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);
--- 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);
--- 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;
}