source: protocols/jabber/jabber.c @ 6a1128d

Last change on this file since 6a1128d was 6a1128d, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-10-09T18:19:05Z

The module now keeps track of all resources available for a buddy. This
means the buddy won't show up offline when one resource goes down (while
there are still others available). It also remembers away state
information for every separate resource. Later this system will be used
to keep track of client capability information (Typing notices, yay...)
and who knows what else.

  • Property mode set to 100644
File size: 8.1 KB
Line 
1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  Jabber module - Main file                                                *
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 <glib.h>
25#include <string.h>
26#include <unistd.h>
27#include <ctype.h>
28#include <stdio.h>
29
30#include "ssl_client.h"
31#include "xmltree.h"
32#include "bitlbee.h"
33#include "jabber.h"
34
35static void jabber_acc_init( account_t *acc )
36{
37        set_t *s;
38       
39        s = set_add( &acc->set, "port", "5222", set_eval_int, acc );
40        s->flags |= ACC_SET_OFFLINE_ONLY;
41       
42        s = set_add( &acc->set, "priority", "0", set_eval_priority, acc );
43       
44        s = set_add( &acc->set, "resource", "BitlBee", NULL, acc );
45        s->flags |= ACC_SET_OFFLINE_ONLY;
46       
47        s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
48        s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
49       
50        s = set_add( &acc->set, "ssl", "false", set_eval_bool, acc );
51        s->flags |= ACC_SET_OFFLINE_ONLY;
52       
53        s = set_add( &acc->set, "tls", "try", set_eval_tls, acc );
54        s->flags |= ACC_SET_OFFLINE_ONLY;
55}
56
57static void jabber_login( account_t *acc )
58{
59        struct gaim_connection *gc = new_gaim_conn( acc );
60        struct jabber_data *jd = g_new0( struct jabber_data, 1 );
61        struct ns_srv_reply *srv = NULL;
62        char *connect_to;
63       
64        jd->gc = gc;
65        gc->proto_data = jd;
66       
67        jd->username = g_strdup( acc->user );
68        jd->server = strchr( jd->username, '@' );
69       
70        if( jd->server == NULL )
71        {
72                hide_login_progress( gc, "Incomplete account name (format it like <username@jabberserver.name>)" );
73                signoff( gc );
74                return;
75        }
76       
77        /* So don't think of free()ing jd->server.. :-) */
78        *jd->server = 0;
79        jd->server ++;
80       
81        jd->node_cache = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, jabber_cache_entry_free );
82        jd->buddies = g_hash_table_new( g_str_hash, g_str_equal );
83       
84        /* Figure out the hostname to connect to. */
85        if( acc->server )
86                connect_to = acc->server;
87        else if( ( srv = srv_lookup( "xmpp-client", "tcp", jd->server ) ) ||
88                 ( srv = srv_lookup( "jabber-client", "tcp", jd->server ) ) )
89                connect_to = srv->name;
90        else
91                connect_to = jd->server;
92       
93        /* For non-SSL connections we can try to use the port # from the SRV
94           reply, but let's not do that when using SSL, SSL usually runs on
95           non-standard ports... */
96        if( set_getbool( &acc->set, "ssl" ) )
97        {
98                jd->ssl = ssl_connect( connect_to, set_getint( &acc->set, "port" ), jabber_connected_ssl, gc );
99                jd->fd = ssl_getfd( jd->ssl );
100        }
101        else
102        {
103                jd->fd = proxy_connect( connect_to, srv ? srv->port : set_getint( &acc->set, "port" ), jabber_connected_plain, gc );
104        }
105       
106        g_free( srv );
107}
108
109static void jabber_close( struct gaim_connection *gc )
110{
111        struct jabber_data *jd = gc->proto_data;
112       
113        jabber_end_stream( gc );
114       
115        if( jd->r_inpa >= 0 )
116                b_event_remove( jd->r_inpa );
117        if( jd->w_inpa >= 0 )
118                b_event_remove( jd->w_inpa );
119       
120        if( jd->ssl )
121                ssl_disconnect( jd->ssl );
122        if( jd->fd >= 0 )
123                closesocket( jd->fd );
124       
125        if( jd->tx_len )
126                g_free( jd->txq );
127       
128        g_hash_table_destroy( jd->node_cache );
129       
130        xt_free( jd->xt );
131       
132        g_free( jd->away_message );
133        g_free( jd->username );
134        g_free( jd );
135}
136
137static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, int len, int away )
138{
139        struct xt_node *node;
140        int st;
141       
142        /*
143        event = xt_new_node( "active", NULL, NULL );
144        xt_add_attr( event, "xlmns", "http://jabber.org/protocol/chatstates" );
145       
146        event = xt_new_node( "x", NULL, xt_new_node( "composing", NULL, NULL ) );
147        xt_add_attr( event, "xmlns", "jabber:x:event" );
148        */
149       
150        node = xt_new_node( "body", message, NULL );
151        node = jabber_make_packet( "message", "chat", who, node );
152        st = jabber_write_packet( gc, node );
153        xt_free_node( node );
154       
155        return st;
156}
157
158static GList *jabber_away_states( struct gaim_connection *gc )
159{
160        static GList *l = NULL;
161        int i;
162       
163        if( l == NULL )
164                for( i = 0; jabber_away_state_list[i].full_name; i ++ )
165                        l = g_list_append( l, (void*) jabber_away_state_list[i].full_name );
166       
167        return l;
168}
169
170static void jabber_get_info( struct gaim_connection *gc, char *who )
171{
172        struct jabber_buddy *bud;
173        struct xt_node *node;
174       
175        bud = jabber_buddy_by_jid( gc, who );
176        while( bud )
177        {
178                serv_got_crap( gc, "Buddy %s/%s (%d) information:\nAway state: %s\nAway message: %s",
179                                   bud->handle, bud->resource, bud->priority,
180                                   bud->away_state ? bud->away_state->full_name : "(none)",
181                                   bud->away_message ? : "(none)" );
182                bud = bud->next;
183        }
184       
185//      node = xt_new_node( "vCard", NULL, NULL );
186//      xt_add_attr( node, "xmlns", "vcard-temp" );
187        node = xt_new_node( "query", NULL, NULL );
188        xt_add_attr( node, "xmlns", "jabber:iq:version" );
189        node = jabber_make_packet( "iq", "get", who, node );
190        // jabber_cache_add( gc, node,  );
191       
192        jabber_write_packet( gc, node );
193}
194
195static void jabber_set_away( struct gaim_connection *gc, char *state_txt, char *message )
196{
197        struct jabber_data *jd = gc->proto_data;
198        struct jabber_away_state *state;
199       
200        /* Save all this info. We need it, for example, when changing the priority setting. */
201        state = (void *) jabber_away_state_by_name( state_txt );
202        jd->away_state = state ? state : (void *) jabber_away_state_list; /* Fall back to "Away" if necessary. */
203        g_free( jd->away_message );
204        jd->away_message = ( message && *message ) ? g_strdup( message ) : NULL;
205       
206        presence_send_update( gc );
207}
208
209static void jabber_add_buddy( struct gaim_connection *gc, char *who )
210{
211        if( jabber_add_to_roster( gc, who, NULL ) )
212                presence_send_request( gc, who, "subscribe" );
213}
214
215static void jabber_remove_buddy( struct gaim_connection *gc, char *who, char *group )
216{
217        if( jabber_remove_from_roster( gc, who ) )
218                presence_send_request( gc, who, "unsubscribe" );
219}
220
221static void jabber_keepalive( struct gaim_connection *gc )
222{
223        /* Just any whitespace character is enough as a keepalive for XMPP sessions. */
224        jabber_write( gc, "\n", 1 );
225       
226        /* This runs the garbage collection every minute, which means every packet
227           is in the cache for about a minute (which should be enough AFAIK). */
228        jabber_cache_clean( gc );
229}
230
231void jabber_init()
232{
233        struct prpl *ret = g_new0( struct prpl, 1 );
234       
235        ret->name = "jabber";
236        ret->login = jabber_login;
237        ret->acc_init = jabber_acc_init;
238        ret->close = jabber_close;
239        ret->send_im = jabber_send_im;
240        ret->away_states = jabber_away_states;
241//      ret->get_status_string = jabber_get_status_string;
242        ret->set_away = jabber_set_away;
243//      ret->set_info = jabber_set_info;
244        ret->get_info = jabber_get_info;
245        ret->add_buddy = jabber_add_buddy;
246        ret->remove_buddy = jabber_remove_buddy;
247//      ret->chat_send = jabber_chat_send;
248//      ret->chat_invite = jabber_chat_invite;
249//      ret->chat_leave = jabber_chat_leave;
250//      ret->chat_open = jabber_chat_open;
251        ret->keepalive = jabber_keepalive;
252//      ret->send_typing = jabber_send_typing;
253        ret->handle_cmp = g_strcasecmp;
254
255        register_protocol( ret );
256}
Note: See TracBrowser for help on using the repository browser.