source: protocols/jabber/io.c @ 21167d2

Last change on this file since 21167d2 was 21167d2, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-09-20T19:42:27Z

It can send a valid (pre-XMPP) login packet. Lots of work to do, still...

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  Jabber module - I/O stuff (plain, SSL), queues, 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 gboolean jabber_write_callback( gpointer data, gint fd, b_input_condition cond );
27
28int jabber_write_packet( struct gaim_connection *gc, struct xt_node *node )
29{
30        char *buf;
31        int st;
32       
33        buf = xt_to_string( node );
34        st = jabber_write( gc, buf, strlen( buf ) );
35        g_free( buf );
36       
37        return st;
38}
39
40int jabber_write( struct gaim_connection *gc, char *buf, int len )
41{
42        struct jabber_data *jd = gc->proto_data;
43       
44        if( jd->tx_len == 0 )
45        {
46                /* If the queue is empty, allocate a new buffer. */
47                jd->tx_len = len;
48                jd->txq = g_memdup( buf, len );
49               
50                /* Try if we can write it immediately so we don't have to do
51                   it via the event handler. If not, add the handler. (In
52                   most cases it probably won't be necessary.) */
53                if( jabber_write_callback( gc, jd->fd, GAIM_INPUT_WRITE ) )
54                        jd->w_inpa = b_input_add( jd->fd, GAIM_INPUT_WRITE, jabber_write_callback, gc );
55        }
56        else
57        {
58                /* Just add it to the buffer if it's already filled. The
59                   event handler is already set. */
60                jd->txq = g_renew( char, jd->txq, jd->tx_len + len );
61                memcpy( jd->txq + jd->tx_len, buf, len );
62                jd->tx_len += len;
63        }
64       
65        /* FIXME: write_callback could've generated a real error! */
66        return 1;
67}
68
69static gboolean jabber_write_callback( gpointer data, gint fd, b_input_condition cond )
70{
71        struct gaim_connection *gc = data;
72        struct jabber_data *jd = gc->proto_data;
73        int st;
74       
75        st = write( jd->fd, jd->txq, jd->tx_len );
76       
77        if( st == jd->tx_len )
78        {
79                /* We wrote everything, clear the buffer. */
80                g_free( jd->txq );
81                jd->txq = NULL;
82                jd->tx_len = 0;
83               
84                return FALSE;
85        }
86        else if( st == 0 || ( st < 0 && !sockerr_again() ) )
87        {
88                hide_login_progress_error( gc, "Short write() to server" );
89                signoff( gc );
90                return FALSE;
91        }
92        else if( st > 0 )
93        {
94                char *s;
95               
96                s = g_memdup( jd->txq + st, jd->tx_len - st );
97                jd->tx_len -= st;
98                g_free( jd->txq );
99                jd->txq = s;
100               
101                return FALSE;
102        }
103        else
104        {
105                /* Just in case we had EINPROGRESS/EAGAIN: */
106               
107                return TRUE;
108        }
109}
110
111static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition cond )
112{
113        struct gaim_connection *gc = data;
114        struct jabber_data *jd = gc->proto_data;
115        char buf[512];
116        int st;
117       
118        st = read( fd, buf, sizeof( buf ) );
119       
120        if( st > 0 )
121        {
122                /* Parse. */
123                if( !xt_feed( jd->xt, buf, st ) )
124                {
125                        hide_login_progress_error( gc, "XML stream error" );
126                        signoff( gc );
127                        return FALSE;
128                }
129               
130                /* Execute all handlers. */
131                if( !xt_handle( jd->xt, NULL ) )
132                {
133                        /* Don't do anything, the handlers should have
134                           aborted the connection already... Or not? FIXME */
135                        return FALSE;
136                }
137               
138                /* Garbage collection. */
139                xt_cleanup( jd->xt, NULL );
140               
141                /* This is a bit hackish, unfortunately. Although xmltree
142                   has nifty event handler stuff, it only calls handlers
143                   when nodes are complete. Since the server should only
144                   send an opening <stream:stream> tag, we have to check
145                   this by hand. :-( */
146                if( !( jd->flags & JFLAG_STREAM_STARTED ) && jd->xt && jd->xt->root )
147                {
148                        if( g_strcasecmp( jd->xt->root->name, "stream:stream" ) == 0 )
149                        {
150                                jd->flags |= JFLAG_STREAM_STARTED;
151                                return jabber_start_auth( gc );
152                        }
153                        else
154                        {
155                                hide_login_progress_error( gc, "XML stream error" );
156                                signoff( gc );
157                                return FALSE;
158                        }
159                }
160        }
161        else if( st == 0 || ( st < 0 && !sockerr_again() ) )
162        {
163                hide_login_progress_error( gc, "Error while reading from server" );
164                signoff( gc );
165                return FALSE;
166        }
167       
168        /* EAGAIN/etc or a successful read. */
169        return TRUE;
170}
171
172static gboolean jabber_start_stream( struct gaim_connection *gc );
173
174gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition cond )
175{
176        struct gaim_connection *gc = data;
177       
178        if( source == -1 )
179        {
180                hide_login_progress( gc, "Could not connect to server" );
181                signoff( gc );
182                return FALSE;
183        }
184       
185        set_login_progress( gc, 1, "Connected to server, logging in" );
186       
187        return jabber_start_stream( gc );
188}
189
190static xt_status jabber_end_of_stream( struct xt_node *node, gpointer data )
191{
192        return XT_ABORT;
193}
194
195static xt_status jabber_pkt_misc( struct xt_node *node, gpointer data )
196{
197        printf( "Received unknown packet:\n" );
198        xt_print( node );
199       
200        return XT_HANDLED;
201}
202
203static const struct xt_handler_entry jabber_handlers[] = {
204        { "stream:stream",      "<root>",               jabber_end_of_stream },
205        { "iq",                 "stream:stream",        jabber_pkt_iq },
206        { "message",            "stream:stream",        jabber_pkt_message },
207        { "presence",           "stream:stream",        jabber_pkt_presence },
208        { NULL,                 "stream:stream",        jabber_pkt_misc },
209        { NULL,                 NULL,                   NULL }
210};
211
212static gboolean jabber_start_stream( struct gaim_connection *gc )
213{
214        struct jabber_data *jd = gc->proto_data;
215        int st;
216        char *greet;
217       
218        /* We'll start our stream now, so prepare everything to receive one
219           from the server too. */
220        xt_free( jd->xt );      /* In case we're RE-starting. */
221        jd->xt = xt_new( gc );
222        jd->xt->handlers = (struct xt_handler_entry*) jabber_handlers;
223       
224        jd->r_inpa = b_input_add( jd->fd, GAIM_INPUT_READ, jabber_read_callback, gc );
225       
226        greet = g_strdup_printf( "<?xml version='1.0' ?>"
227                                 "<stream:stream to=\"%s\" xmlns=\"jabber:client\" "
228                                  "xmlns:stream=\"http://etherx.jabber.org/streams\">", jd->server );
229        /* Add this when TLS and SASL are supported? */
230        // version=\"1.0\">"
231       
232        st = jabber_write( gc, greet, strlen( greet ) );
233       
234        g_free( greet );
235       
236        return st;
237}
Note: See TracBrowser for help on using the repository browser.