source: protocols/jabber/message.c @ 1444be5

Last change on this file since 1444be5 was 1444be5, checked in by Michael Stapelberg <michael@…>, at 2012-10-17T07:23:00Z

Implement jabber message receipts (XEP-0184)

This change will make BitlBee acknowledge messages when requested.
It will not request message receipts from other clients, mainly because I am
not sure if this feature can be mapped to IRC cleanly.

  • Property mode set to 100644
File size: 6.5 KB
Line 
1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  Jabber module - Handling of message(s) (tags), etc                       *
5*                                                                           *
6*  Copyright 2006 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 unsigned int next_receipt_id = 1;
27
28xt_status jabber_pkt_message( struct xt_node *node, gpointer data )
29{
30        struct im_connection *ic = data;
31        struct jabber_data *jd = ic->proto_data;
32        char *from = xt_find_attr( node, "from" );
33        char *type = xt_find_attr( node, "type" );
34        char *id = xt_find_attr( node, "id" );
35        struct xt_node *body = xt_find_node( node->children, "body" ), *c;
36        struct xt_node *request = xt_find_node( node->children, "request" );
37        struct xt_node *received, *receipt;
38        struct jabber_buddy *bud = NULL;
39        char *s, *room = NULL, *reason = NULL;
40       
41        if( !from )
42                return XT_HANDLED; /* Consider this packet corrupted. */
43
44        if( request && id )
45        {
46                /* Send a message receipt (XEP-0184), looking like this:
47                 * <message
48                 *  from='kingrichard@royalty.england.lit/throne'
49                 *  id='bi29sg183b4v'
50                 *  to='northumberland@shakespeare.lit/westminster'>
51                 *  <received xmlns='urn:xmpp:receipts' id='richard2-4.1.247'/>
52                 * </message> */
53                received = xt_new_node( "received", NULL, NULL );
54                xt_add_attr( received, "xmlns", XMLNS_RECEIPTS );
55                xt_add_attr( received, "id", id );
56                receipt = jabber_make_packet( "message", NULL, from, received );
57                xt_add_attr( receipt, "from", jd->me );
58
59                char *id = g_strdup_printf( "%sRCPT%05x", JABBER_PACKET_ID, ( next_receipt_id++ ) & 0xfffff );
60                xt_add_attr( receipt, "id", id );
61                g_free( id );
62
63                jabber_write_packet( ic, receipt );
64                xt_free_node( receipt );
65        }
66       
67        bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT );
68       
69        if( type && strcmp( type, "error" ) == 0 )
70        {
71                /* Handle type=error packet. */
72        }
73        else if( type && from && strcmp( type, "groupchat" ) == 0 )
74        {
75                jabber_chat_pkt_message( ic, bud, node );
76        }
77        else /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */
78        {
79                GString *fullmsg = g_string_new( "" );
80
81                for( c = node->children; ( c = xt_find_node( c, "x" ) ); c = c->next )
82                {
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                        {
89                                /* This is an invitation. Set some vars which
90                                   will be passed to imcb_chat_invite() below. */
91                                room = from;
92                                if( ( from = xt_find_attr( inv, "from" ) ) == NULL )
93                                        from = room;
94                                if( ( inv = xt_find_node( inv->children, "reason" ) ) && inv->text_len > 0 )
95                                        reason = inv->text;
96                        }
97                }
98               
99                if( ( s = strchr( from, '/' ) ) )
100                {
101                        if( bud )
102                        {
103                                bud->last_msg = time( NULL );
104                                from = bud->ext_jid ? bud->ext_jid : bud->bare_jid;
105                        }
106                        else
107                                *s = 0; /* We need to generate a bare JID now. */
108                }
109               
110                if( type && strcmp( type, "headline" ) == 0 )
111                {
112                        if( ( c = xt_find_node( node->children, "subject" ) ) && c->text_len > 0 )
113                                g_string_append_printf( fullmsg, "Headline: %s\n", c->text );
114                       
115                        /* <x xmlns="jabber:x:oob"><url>http://....</url></x> can contain a URL, it seems. */
116                        for( c = node->children; c; c = c->next )
117                        {
118                                struct xt_node *url;
119                               
120                                if( ( url = xt_find_node( c->children, "url" ) ) && url->text_len > 0 )
121                                        g_string_append_printf( fullmsg, "URL: %s\n", url->text );
122                        }
123                }
124                else if( ( c = xt_find_node( node->children, "subject" ) ) && c->text_len > 0 &&
125                         ( !bud || !( bud->flags & JBFLAG_HIDE_SUBJECT ) ) )
126                {
127                        g_string_append_printf( fullmsg, "<< \002BitlBee\002 - Message with subject: %s >>\n", c->text );
128                        if( bud )
129                                bud->flags |= JBFLAG_HIDE_SUBJECT;
130                }
131                else if( bud && !c )
132                {
133                        /* Yeah, possibly we're hiding changes to this field now. But nobody uses
134                           this for anything useful anyway, except GMail when people reply to an
135                           e-mail via chat, repeating the same subject all the time. I don't want
136                           to have to remember full subject strings for everyone. */
137                        bud->flags &= ~JBFLAG_HIDE_SUBJECT;
138                }
139               
140                if( body && body->text_len > 0 ) /* Could be just a typing notification. */
141                        fullmsg = g_string_append( fullmsg, body->text );
142               
143                if( fullmsg->len > 0 )
144                        imcb_buddy_msg( ic, from, fullmsg->str,
145                                        0, jabber_get_timestamp( node ) );
146                if( room )
147                        imcb_chat_invite( ic, room, from, reason );
148               
149                g_string_free( fullmsg, TRUE );
150               
151                /* Handling of incoming typing notifications. */
152                if( bud == NULL )
153                {
154                        /* Can't handle these for unknown buddies. */
155                }
156                else if( xt_find_node( node->children, "composing" ) )
157                {
158                        bud->flags |= JBFLAG_DOES_XEP85;
159                        imcb_buddy_typing( ic, from, OPT_TYPING );
160                }
161                /* No need to send a "stopped typing" signal when there's a message. */
162                else if( xt_find_node( node->children, "active" ) && ( body == NULL ) )
163                {
164                        bud->flags |= JBFLAG_DOES_XEP85;
165                        imcb_buddy_typing( ic, from, 0 );
166                }
167                else if( xt_find_node( node->children, "paused" ) )
168                {
169                        bud->flags |= JBFLAG_DOES_XEP85;
170                        imcb_buddy_typing( ic, from, OPT_THINKING );
171                }
172               
173                if( s )
174                        *s = '/'; /* And convert it back to a full JID. */
175        }
176       
177        return XT_HANDLED;
178}
Note: See TracBrowser for help on using the repository browser.