source: protocols/jabber/message.c @ ea39049

Last change on this file since ea39049 was d11ccbf, checked in by dequis <dx@…>, at 2015-12-16T15:35:04Z

hipchat: Implement their own variant of self-messages (not working yet)

Reuses part of the carbons code, but it's not like it at all.

To be able to receive these messages at all, a different cap node
whitelisted by them is required. I could have used one of the official
clients, but let's try to get things done the right way.

This will start working once they make that change in their servers,
right now this is still in their ticket backlog. I'm merging this now
because it's harmless and nice to have as part of the upcoming release.

  • Property mode set to 100644
File size: 7.9 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
26static xt_status jabber_pkt_message_normal(struct xt_node *node, gpointer data, gboolean carbons_sent)
27{
28        struct im_connection *ic = data;
29        struct jabber_data *jd = ic->proto_data;
30        char *from = xt_find_attr(node, carbons_sent ? "to" : "from");
31        char *type = xt_find_attr(node, "type");
32        char *id = xt_find_attr(node, "id");
33        struct xt_node *body = xt_find_node(node->children, "body"), *c;
34        struct xt_node *request = xt_find_node(node->children, "request");
35        struct jabber_buddy *bud = NULL;
36        char *s, *room = NULL, *reason = NULL;
37
38        if (!from) {
39                return XT_HANDLED; /* Consider this packet corrupted. */
40        }
41
42        /* try to detect hipchat's own version of self-messages */
43        if (jd->flags & JFLAG_HIPCHAT) {
44                struct xt_node *c;
45
46                if ((c = xt_find_node_by_attr(node->children, "delay", "xmlns", XMLNS_DELAY)) &&
47                    (s = xt_find_attr(c, "from_jid")) &&
48                    jabber_compare_jid(s, jd->me)) {
49                        carbons_sent = TRUE;
50                }
51        }
52
53        if (request && id && g_strcmp0(type, "groupchat") != 0 && !carbons_sent) {
54                /* Send a message receipt (XEP-0184), looking like this:
55                 * <message from='...' id='...' to='...'>
56                 *  <received xmlns='urn:xmpp:receipts' id='richard2-4.1.247'/>
57                 * </message>
58                 *
59                 * MUC messages are excluded, since receipts aren't supposed to be sent over MUCs
60                 * (XEP-0184 section 5.3) and replying to those may result in 'forbidden' errors.
61                 */
62                struct xt_node *received, *receipt;
63
64                received = xt_new_node("received", NULL, NULL);
65                xt_add_attr(received, "xmlns", XMLNS_RECEIPTS);
66                xt_add_attr(received, "id", id);
67                receipt = jabber_make_packet("message", NULL, from, received);
68
69                jabber_write_packet(ic, receipt);
70                xt_free_node(receipt);
71        }
72
73        bud = jabber_buddy_by_jid(ic, from, GET_BUDDY_EXACT);
74
75        if (type && strcmp(type, "error") == 0) {
76                /* Handle type=error packet. */
77        } else if (type && from && strcmp(type, "groupchat") == 0) {
78                jabber_chat_pkt_message(ic, bud, node);
79        } else { /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */
80                GString *fullmsg = g_string_new("");
81
82                for (c = node->children; (c = xt_find_node(c, "x")); c = c->next) {
83                        char *ns = xt_find_attr(c, "xmlns");
84                        struct xt_node *inv;
85
86                        if (ns && strcmp(ns, XMLNS_MUC_USER) == 0 &&
87                            (inv = xt_find_node(c->children, "invite"))) {
88                                /* This is an invitation. Set some vars which
89                                   will be passed to imcb_chat_invite() below. */
90                                room = from;
91                                if ((from = xt_find_attr(inv, "from")) == NULL) {
92                                        from = room;
93                                }
94                                if ((inv = xt_find_node(inv->children, "reason")) && inv->text_len > 0) {
95                                        reason = inv->text;
96                                }
97                        }
98                }
99
100                if ((s = strchr(from, '/'))) {
101                        if (bud) {
102                                bud->last_msg = time(NULL);
103                                from = bud->ext_jid ? bud->ext_jid : bud->bare_jid;
104                        } else {
105                                *s = 0; /* We need to generate a bare JID now. */
106                        }
107                }
108
109                if (type && strcmp(type, "headline") == 0) {
110                        if ((c = xt_find_node(node->children, "subject")) && c->text_len > 0) {
111                                g_string_append_printf(fullmsg, "Headline: %s\n", c->text);
112                        }
113
114                        /* <x xmlns="jabber:x:oob"><url>http://....</url></x> can contain a URL, it seems. */
115                        for (c = node->children; c; c = c->next) {
116                                struct xt_node *url;
117
118                                if ((url = xt_find_node(c->children, "url")) && url->text_len > 0) {
119                                        g_string_append_printf(fullmsg, "URL: %s\n", url->text);
120                                }
121                        }
122                } else if ((c = xt_find_node(node->children, "subject")) && c->text_len > 0 &&
123                           (!bud || !(bud->flags & JBFLAG_HIDE_SUBJECT))) {
124                        g_string_append_printf(fullmsg, "<< \002BitlBee\002 - Message with subject: %s >>\n", c->text);
125                        if (bud) {
126                                bud->flags |= JBFLAG_HIDE_SUBJECT;
127                        }
128                } else if (bud && !c) {
129                        /* Yeah, possibly we're hiding changes to this field now. But nobody uses
130                           this for anything useful anyway, except GMail when people reply to an
131                           e-mail via chat, repeating the same subject all the time. I don't want
132                           to have to remember full subject strings for everyone. */
133                        bud->flags &= ~JBFLAG_HIDE_SUBJECT;
134                }
135
136                if (body && body->text_len > 0) { /* Could be just a typing notification. */
137                        fullmsg = g_string_append(fullmsg, body->text);
138                }
139
140                if (fullmsg->len > 0) {
141                        imcb_buddy_msg(ic, from, fullmsg->str,
142                                       carbons_sent ? OPT_SELFMESSAGE : 0, jabber_get_timestamp(node));
143                }
144                if (room) {
145                        imcb_chat_invite(ic, room, from, reason);
146                }
147
148                g_string_free(fullmsg, TRUE);
149
150                /* Handling of incoming typing notifications. */
151                if (bud == NULL || carbons_sent) {
152                        /* Can't handle these for unknown buddies.
153                           And ignore them if it's just carbons */
154                } else if (xt_find_node(node->children, "composing")) {
155                        bud->flags |= JBFLAG_DOES_XEP85;
156                        imcb_buddy_typing(ic, from, OPT_TYPING);
157                }
158                else if (xt_find_node(node->children, "active")) {
159                        bud->flags |= JBFLAG_DOES_XEP85;
160
161                        /* No need to send a "stopped typing" signal when there's a message. */
162                        if (body == NULL) {
163                                imcb_buddy_typing(ic, from, 0);
164                        }
165                } else if (xt_find_node(node->children, "paused")) {
166                        bud->flags |= JBFLAG_DOES_XEP85;
167                        imcb_buddy_typing(ic, from, OPT_THINKING);
168                }
169
170                if (s) {
171                        *s = '/'; /* And convert it back to a full JID. */
172                }
173        }
174
175        return XT_HANDLED;
176}
177
178static xt_status jabber_carbons_message(struct xt_node *node, gpointer data)
179{
180        struct im_connection *ic = data;
181        struct xt_node *wrap, *fwd, *msg;
182        gboolean carbons_sent;
183
184        if ((wrap = xt_find_node(node->children, "received"))) {
185                carbons_sent = FALSE;
186        } else if ((wrap = xt_find_node(node->children, "sent"))) {
187                carbons_sent = TRUE;
188        }
189
190        if (wrap == NULL || g_strcmp0(xt_find_attr(wrap, "xmlns"), XMLNS_CARBONS) != 0) {
191                return XT_NEXT;
192        }
193
194        if (!(fwd = xt_find_node(wrap->children, "forwarded")) ||
195             (g_strcmp0(xt_find_attr(fwd, "xmlns"), XMLNS_FORWARDING) != 0) ||
196            !(msg = xt_find_node(fwd->children, "message"))) {
197                imcb_log(ic, "Error: Invalid carbons message received");
198                return XT_ABORT;
199        }
200
201        return jabber_pkt_message_normal(msg, data, carbons_sent);
202}
203
204xt_status jabber_pkt_message(struct xt_node *node, gpointer data)
205{
206        struct im_connection *ic = data;
207        struct jabber_data *jd = ic->proto_data;
208        char *from = xt_find_attr(node, "from");
209
210        if (jabber_compare_jid(jd->me, from)) {    /* Probably a Carbons message */
211                xt_status st = jabber_carbons_message(node, data);
212                if (st == XT_HANDLED || st == XT_ABORT) {
213                        return st;
214                }
215        }
216        return jabber_pkt_message_normal(node, data, FALSE);
217}
Note: See TracBrowser for help on using the repository browser.