source: protocols/jabber/presence.c @ dd34575

Last change on this file since dd34575 was 8c1eb80, checked in by Wilmer van der Gaast <wilmer@…>, at 2008-02-03T16:59:39Z

Implemented XEP-0115. This adds some info to the <presence/> tags so
clients interested in capabilities can cache discovery info, so they don't
have to ask about it every time you/they log in.

  • Property mode set to 100644
File size: 8.7 KB
RevLine 
[f06894d]1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
[21167d2]4*  Jabber module - Handling of presence (tags), etc                         *
[f06894d]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
26xt_status jabber_pkt_presence( struct xt_node *node, gpointer data )
27{
[0da65d5]28        struct im_connection *ic = data;
[f06894d]29        char *from = xt_find_attr( node, "from" );
[4a0614e]30        char *type = xt_find_attr( node, "type" );      /* NULL should mean the person is online. */
[8c1eb80]31        struct xt_node *c, *cap;
[e7f8838]32        struct jabber_buddy *bud, *send_presence = NULL;
33        int is_chat = 0;
[788a1af]34        char *s;
[f06894d]35       
[4a0614e]36        if( !from )
37                return XT_HANDLED;
38       
[e35d1a1]39        if( ( s = strchr( from, '/' ) ) )
40        {
41                *s = 0;
[5bd21df]42                if( jabber_chat_by_jid( ic, from ) )
[e35d1a1]43                        is_chat = 1;
44                *s = '/';
45        }
46       
[4a0614e]47        if( type == NULL )
[6a1128d]48        {
[0da65d5]49                if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) )
[a21a8ac]50                {
[0da65d5]51                        if( set_getbool( &ic->irc->set, "debug" ) )
[43462708]52                                imcb_log( ic, "Warning: Could not handle presence information from JID: %s", from );
[8eb10c9]53                        return XT_HANDLED;
[a21a8ac]54                }
[6a1128d]55               
56                g_free( bud->away_message );
57                if( ( c = xt_find_node( node->children, "status" ) ) && c->text_len > 0 )
58                        bud->away_message = g_strdup( c->text );
59                else
60                        bud->away_message = NULL;
61               
62                if( ( c = xt_find_node( node->children, "show" ) ) && c->text_len > 0 )
[6bbb939]63                {
[6a1128d]64                        bud->away_state = (void*) jabber_away_state_by_code( c->text );
[6bbb939]65                }
[6a1128d]66                else
[a21a8ac]67                {
[6a1128d]68                        bud->away_state = NULL;
[a21a8ac]69                        /* Let's only set last_act if there's *no* away state,
70                           since it could be some auto-away thingy. */
71                        bud->last_act = time( NULL );
72                }
[6a1128d]73               
74                if( ( c = xt_find_node( node->children, "priority" ) ) && c->text_len > 0 )
75                        bud->priority = atoi( c->text );
76                else
77                        bud->priority = 0;
78               
[8c1eb80]79                if( bud && ( cap = xt_find_node( node->children, "c" ) ) &&
80                    ( s = xt_find_attr( cap, "xmlns" ) ) && strcmp( s, XMLNS_CAPS ) == 0 )
81                {
82                        /* This <presence> stanza includes an XEP-0115
83                           capabilities part. Not too interesting, but we can
84                           see if it has an ext= attribute. */
85                        s = xt_find_attr( cap, "ext" );
86                        if( s && ( strstr( s, "cstates" ) || strstr( s, "chatstate" ) ) )
87                                bud->flags |= JBFLAG_DOES_XEP85;
88                       
89                        /* This field can contain more information like xhtml
90                           support, but we don't support that ourselves.
91                           Officially the ext= tag was deprecated, but enough
92                           clients do send it.
93                           
94                           (I'm aware that this is not the right way to use
95                           this field.) See for an explanation of ext=:
96                           http://www.xmpp.org/extensions/attic/xep-0115-1.3.html*/
97                }
98               
[e35d1a1]99                if( is_chat )
100                        jabber_chat_pkt_presence( ic, bud, node );
[e7f8838]101                else
102                        send_presence = jabber_buddy_by_jid( ic, bud->bare_jid, 0 );
[6a1128d]103        }
[4a0614e]104        else if( strcmp( type, "unavailable" ) == 0 )
[6a1128d]105        {
[3a80471]106                if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL )
[788a1af]107                {
[0da65d5]108                        if( set_getbool( &ic->irc->set, "debug" ) )
[43462708]109                                imcb_log( ic, "Warning: Received presence information from unknown JID: %s", from );
[788a1af]110                        return XT_HANDLED;
111                }
112               
[e35d1a1]113                /* Handle this before we delete the JID. */
114                if( is_chat )
115                {
116                        jabber_chat_pkt_presence( ic, bud, node );
117                }
118               
[3a80471]119                if( strchr( from, '/' ) == NULL )
120                        /* Sometimes servers send a type="unavailable" from a
121                           bare JID, which should mean that suddenly all
122                           resources for this JID disappeared. */
123                        jabber_buddy_remove_bare( ic, from );
124                else
125                        jabber_buddy_remove( ic, from );
[6a1128d]126               
[e35d1a1]127                if( is_chat )
128                {
129                        /* Nothing else to do for now? */
130                }
131                else if( ( s = strchr( from, '/' ) ) )
[0d3f30f]132                {
133                        *s = 0;
[6a1128d]134               
[2758cfe]135                        /* If another resource is still available, send its presence
136                           information. */
[e7f8838]137                        if( ( send_presence = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL )
[2758cfe]138                        {
139                                /* Otherwise, count him/her as offline now. */
[6bbb939]140                                imcb_buddy_status( ic, from, 0, NULL, NULL );
[2758cfe]141                        }
[0d3f30f]142                       
143                        *s = '/';
144                }
145                else
146                {
[6bbb939]147                        imcb_buddy_status( ic, from, 0, NULL, NULL );
[0d3f30f]148                }
[6a1128d]149        }
[8e5e2e9]150        else if( strcmp( type, "subscribe" ) == 0 )
[6a1128d]151        {
[0da65d5]152                jabber_buddy_ask( ic, from );
[6a1128d]153        }
[8e5e2e9]154        else if( strcmp( type, "subscribed" ) == 0 )
[6a1128d]155        {
[0d3f30f]156                /* Not sure about this one, actually... */
[84b045d]157                imcb_log( ic, "%s just accepted your authorization request", from );
[6a1128d]158        }
[8e5e2e9]159        else if( strcmp( type, "unsubscribe" ) == 0 || strcmp( type, "unsubscribed" ) == 0 )
160        {
161                /* Do nothing here. Plenty of control freaks or over-curious
162                   souls get excited when they can see who still has them in
163                   their buddy list and who finally removed them. Somehow I
164                   got the impression that those are the people who get
165                   removed from many buddy lists for "some" reason...
166                   
167                   If you're one of those people, this is your chance to write
168                   your first line of code in C... */
169        }
[6266fca]170        else if( strcmp( type, "error" ) == 0 )
171        {
[5bd21df]172                return jabber_cache_handle_packet( ic, node );
[1baaef8]173               
[5bd21df]174                /*
175                struct jabber_error *err;
[1baaef8]176                if( ( c = xt_find_node( node->children, "error" ) ) )
177                {
178                        err = jabber_error_parse( c, XMLNS_STANZA_ERROR );
179                        imcb_error( ic, "Stanza (%s) error: %s%s%s", node->name,
180                                    err->code, err->text ? ": " : "",
181                                    err->text ? err->text : "" );
182                        jabber_error_free( err );
[5bd21df]183                } */
[6266fca]184        }
[e7f8838]185
186        if( send_presence )
187        {
[dded27d]188                int is_away = 0;
[e7f8838]189
190                if( send_presence->away_state && !( *send_presence->away_state->code == 0 ||
191                    strcmp( send_presence->away_state->code, "chat" ) == 0 ) )
192                        is_away = OPT_AWAY;
193
194                imcb_buddy_status( ic, send_presence->bare_jid, OPT_LOGGED_IN | is_away,
195                                   ( is_away && send_presence->away_state ) ?
196                                   send_presence->away_state->full_name : NULL,
197                                   send_presence->away_message );
198        }
[4a0614e]199       
[f06894d]200        return XT_HANDLED;
201}
202
[172a73f1]203/* Whenever presence information is updated, call this function to inform the
204   server. */
[0da65d5]205int presence_send_update( struct im_connection *ic )
[deff040]206{
[0da65d5]207        struct jabber_data *jd = ic->proto_data;
[8c1eb80]208        struct xt_node *node, *cap;
[172a73f1]209        char *show = jd->away_state->code;
210        char *status = jd->away_message;
[2d317bb]211        struct groupchat *c;
[deff040]212        int st;
213       
[172a73f1]214        node = jabber_make_packet( "presence", NULL, NULL, NULL );
[0da65d5]215        xt_add_child( node, xt_new_node( "priority", set_getstr( &ic->acc->set, "priority" ), NULL ) );
[5e202b0]216        if( show && *show )
[deff040]217                xt_add_child( node, xt_new_node( "show", show, NULL ) );
218        if( status )
219                xt_add_child( node, xt_new_node( "status", status, NULL ) );
220       
[8c1eb80]221        /* This makes the packet slightly bigger, but clients interested in
222           capabilities can now cache the discovery info. This reduces the
223           usual post-login iq-flood. See XEP-0115. At least libpurple and
224           Trillian seem to do this right. */
225        cap = xt_new_node( "c", NULL, NULL );
226        xt_add_attr( cap, "xmlns", XMLNS_CAPS );
227        xt_add_attr( cap, "node", "http://bitlbee.org/xmpp/caps" );
228        xt_add_attr( cap, "ver", BITLBEE_VERSION ); /* The XEP wants this hashed, but nobody's doing that. */
229        xt_add_child( node, cap );
230       
[0da65d5]231        st = jabber_write_packet( ic, node );
[deff040]232       
[2d317bb]233        /* Have to send this update to all groupchats too, the server won't
234           do this automatically. */
235        for( c = ic->groupchats; c && st; c = c->next )
236        {
237                struct jabber_chat *jc = c->data;
238               
[9c9b37c]239                xt_add_attr( node, "to", jc->my_full_jid );
[2d317bb]240                st = jabber_write_packet( ic, node );
241        }
242       
[deff040]243        xt_free_node( node );
244        return st;
245}
[cfbb3a6]246
247/* Send a subscribe/unsubscribe request to a buddy. */
[0da65d5]248int presence_send_request( struct im_connection *ic, char *handle, char *request )
[cfbb3a6]249{
250        struct xt_node *node;
251        int st;
252       
253        node = jabber_make_packet( "presence", NULL, NULL, NULL );
254        xt_add_attr( node, "to", handle );
255        xt_add_attr( node, "type", request );
256       
[0da65d5]257        st = jabber_write_packet( ic, node );
[cfbb3a6]258       
259        xt_free_node( node );
260        return st;
261}
Note: See TracBrowser for help on using the repository browser.