source: protocols/jabber/message.c @ 4e365ce

Last change on this file since 4e365ce was 5307e88, checked in by dequis <dx@…>, at 2015-10-21T06:24:08Z

jabber: Fix XEP85 detection (typing) between two bitlbee users

Fixes trac ticket 1143: https://bugs.bitlbee.org/bitlbee/ticket/1143

The "correct" way to discover XEP85 support is to send a discovery
query. We take a more conservative approach: if the irc client claims to
support typing (by sending CTCP TYPING at least once), we send an
<active> tag along with next chat message, and set JBFLAG_PROBED_XEP85.
The logic for that stuff is in jabber_buddy_msg().

That's all neat and clever and actually works fine. What was broken was
the detection side. Whenever a <composing>, <active> or <pause> is
received, the buddy is marked as supporting XEP85. However the <active>
tag had an additional check:

/* No need to send a "stopped typing" signal when there's a message. */
else if (xt_find_node(node->children, "active") && (body == NULL)) {

It skipped the tag completely if it had a message too.

This was changed to move the body == NULL condition inside, so that the
flag is set.

Took me longer to write this message than the diff itself. But even
longer to actually decide to debug this behavior. I'm the one who
submitted that ticket, one year and a half ago. Yep.

  • Property mode set to 100644
File size: 6.1 KB
Line 
1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  Jabber module - Handling of message(s) (tags), etc                       *
5*                                                                           *
6*  Copyright 2006-2012 Wilmer van der Gaast <wilmer@gaast.net>              *
7*                                                                           *
8*  This program is free software; you can redistribute it and/or modify     *
9*  it under the terms of the GNU General Public License as published by     *
10*  the Free Software Foundation; either version 2 of the License, or        *
11*  (at your option) any later version.                                      *
12*                                                                           *
13*  This program is distributed in the hope that it will be useful,          *
14*  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
15*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
16*  GNU General Public License for more details.                             *
17*                                                                           *
18*  You should have received a copy of the GNU General Public License along  *
19*  with this program; if not, write to the Free Software Foundation, Inc.,  *
20*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              *
21*                                                                           *
22\***************************************************************************/
23
24#include "jabber.h"
25
26xt_status jabber_pkt_message(struct xt_node *node, gpointer data)
27{
28        struct im_connection *ic = data;
29        char *from = xt_find_attr(node, "from");
30        char *type = xt_find_attr(node, "type");
31        char *id = xt_find_attr(node, "id");
32        struct xt_node *body = xt_find_node(node->children, "body"), *c;
33        struct xt_node *request = xt_find_node(node->children, "request");
34        struct jabber_buddy *bud = NULL;
35        char *s, *room = NULL, *reason = NULL;
36
37        if (!from) {
38                return XT_HANDLED; /* Consider this packet corrupted. */
39
40        }
41        if (request && id) {
42                /* Send a message receipt (XEP-0184), looking like this:
43                 * <message
44                 *  from='kingrichard@royalty.england.lit/throne'
45                 *  id='bi29sg183b4v'
46                 *  to='northumberland@shakespeare.lit/westminster'>
47                 *  <received xmlns='urn:xmpp:receipts' id='richard2-4.1.247'/>
48                 * </message> */
49                struct xt_node *received, *receipt;
50
51                received = xt_new_node("received", NULL, NULL);
52                xt_add_attr(received, "xmlns", XMLNS_RECEIPTS);
53                xt_add_attr(received, "id", id);
54                receipt = jabber_make_packet("message", NULL, from, received);
55
56                jabber_write_packet(ic, receipt);
57                xt_free_node(receipt);
58        }
59
60        bud = jabber_buddy_by_jid(ic, from, GET_BUDDY_EXACT);
61
62        if (type && strcmp(type, "error") == 0) {
63                /* Handle type=error packet. */
64        } else if (type && from && strcmp(type, "groupchat") == 0) {
65                jabber_chat_pkt_message(ic, bud, node);
66        } else { /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */
67                GString *fullmsg = g_string_new("");
68
69                for (c = node->children; (c = xt_find_node(c, "x")); c = c->next) {
70                        char *ns = xt_find_attr(c, "xmlns");
71                        struct xt_node *inv;
72
73                        if (ns && strcmp(ns, XMLNS_MUC_USER) == 0 &&
74                            (inv = xt_find_node(c->children, "invite"))) {
75                                /* This is an invitation. Set some vars which
76                                   will be passed to imcb_chat_invite() below. */
77                                room = from;
78                                if ((from = xt_find_attr(inv, "from")) == NULL) {
79                                        from = room;
80                                }
81                                if ((inv = xt_find_node(inv->children, "reason")) && inv->text_len > 0) {
82                                        reason = inv->text;
83                                }
84                        }
85                }
86
87                if ((s = strchr(from, '/'))) {
88                        if (bud) {
89                                bud->last_msg = time(NULL);
90                                from = bud->ext_jid ? bud->ext_jid : bud->bare_jid;
91                        } else {
92                                *s = 0; /* We need to generate a bare JID now. */
93                        }
94                }
95
96                if (type && strcmp(type, "headline") == 0) {
97                        if ((c = xt_find_node(node->children, "subject")) && c->text_len > 0) {
98                                g_string_append_printf(fullmsg, "Headline: %s\n", c->text);
99                        }
100
101                        /* <x xmlns="jabber:x:oob"><url>http://....</url></x> can contain a URL, it seems. */
102                        for (c = node->children; c; c = c->next) {
103                                struct xt_node *url;
104
105                                if ((url = xt_find_node(c->children, "url")) && url->text_len > 0) {
106                                        g_string_append_printf(fullmsg, "URL: %s\n", url->text);
107                                }
108                        }
109                } else if ((c = xt_find_node(node->children, "subject")) && c->text_len > 0 &&
110                           (!bud || !(bud->flags & JBFLAG_HIDE_SUBJECT))) {
111                        g_string_append_printf(fullmsg, "<< \002BitlBee\002 - Message with subject: %s >>\n", c->text);
112                        if (bud) {
113                                bud->flags |= JBFLAG_HIDE_SUBJECT;
114                        }
115                } else if (bud && !c) {
116                        /* Yeah, possibly we're hiding changes to this field now. But nobody uses
117                           this for anything useful anyway, except GMail when people reply to an
118                           e-mail via chat, repeating the same subject all the time. I don't want
119                           to have to remember full subject strings for everyone. */
120                        bud->flags &= ~JBFLAG_HIDE_SUBJECT;
121                }
122
123                if (body && body->text_len > 0) { /* Could be just a typing notification. */
124                        fullmsg = g_string_append(fullmsg, body->text);
125                }
126
127                if (fullmsg->len > 0) {
128                        imcb_buddy_msg(ic, from, fullmsg->str,
129                                       0, jabber_get_timestamp(node));
130                }
131                if (room) {
132                        imcb_chat_invite(ic, room, from, reason);
133                }
134
135                g_string_free(fullmsg, TRUE);
136
137                /* Handling of incoming typing notifications. */
138                if (bud == NULL) {
139                        /* Can't handle these for unknown buddies. */
140                } else if (xt_find_node(node->children, "composing")) {
141                        bud->flags |= JBFLAG_DOES_XEP85;
142                        imcb_buddy_typing(ic, from, OPT_TYPING);
143                }
144                else if (xt_find_node(node->children, "active")) {
145                        bud->flags |= JBFLAG_DOES_XEP85;
146
147                        /* No need to send a "stopped typing" signal when there's a message. */
148                        if (body == NULL) {
149                                imcb_buddy_typing(ic, from, 0);
150                        }
151                } else if (xt_find_node(node->children, "paused")) {
152                        bud->flags |= JBFLAG_DOES_XEP85;
153                        imcb_buddy_typing(ic, from, OPT_THINKING);
154                }
155
156                if (s) {
157                        *s = '/'; /* And convert it back to a full JID. */
158                }
159        }
160
161        return XT_HANDLED;
162}
Note: See TracBrowser for help on using the repository browser.