aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/jabber/io.c
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2006-09-22 18:56:58 +0200
committerWilmer van der Gaast <wilmer@gaast.net>2006-09-22 18:56:58 +0200
commit8d7429102adf8dce6844f2f3da2723d1f87c6442 (patch)
tree78a178e4798f8f11ac5590137efc0642aeea6378 /protocols/jabber/io.c
parent59974884ba72d6e8fa008d07ee93bd228d30a99c (diff)
Fixed return value on incomplete write()s in write handler, protection
against write()ing to sockets that are closed already, hopefully sane detection for SASL support, and only sending type=unavailable presence tag to logged in sessions.
Diffstat (limited to 'protocols/jabber/io.c')
-rw-r--r--protocols/jabber/io.c67
1 files changed, 58 insertions, 9 deletions
diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c
index c7c1d8d9..8f2ce0f1 100644
--- a/protocols/jabber/io.c
+++ b/protocols/jabber/io.c
@@ -72,6 +72,9 @@ static gboolean jabber_write_callback( gpointer data, gint fd, b_input_condition
struct jabber_data *jd = gc->proto_data;
int st;
+ if( jd->fd == -1 )
+ return FALSE;
+
st = write( jd->fd, jd->txq, jd->tx_len );
if( st == jd->tx_len )
@@ -85,6 +88,10 @@ static gboolean jabber_write_callback( gpointer data, gint fd, b_input_condition
}
else if( st == 0 || ( st < 0 && !sockerr_again() ) )
{
+ /* Set fd to -1 to make sure we won't write to it anymore. */
+ closesocket( jd->fd ); /* Shouldn't be necessary after errors? */
+ jd->fd = -1;
+
hide_login_progress_error( gc, "Short write() to server" );
signoff( gc );
return FALSE;
@@ -98,7 +105,7 @@ static gboolean jabber_write_callback( gpointer data, gint fd, b_input_condition
g_free( jd->txq );
jd->txq = s;
- return FALSE;
+ return TRUE;
}
else
{
@@ -115,6 +122,9 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition
char buf[512];
int st;
+ if( jd->fd == -1 )
+ return FALSE;
+
st = read( fd, buf, sizeof( buf ) );
if( st > 0 )
@@ -138,7 +148,6 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition
if( jd->flags & JFLAG_STREAM_RESTART )
{
jd->flags &= ~JFLAG_STREAM_RESTART;
- xt_reset( jd->xt );
jabber_start_stream( gc );
}
@@ -155,7 +164,12 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition
if( g_strcasecmp( jd->xt->root->name, "stream:stream" ) == 0 )
{
jd->flags |= JFLAG_STREAM_STARTED;
- return jabber_start_auth( gc );
+
+ /* If there's no version attribute, assume
+ this is an old server that can't do SASL
+ authentication. */
+ if( !sasl_supported( gc ) )
+ return jabber_start_iq_auth( gc );
}
else
{
@@ -167,6 +181,9 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition
}
else if( st == 0 || ( st < 0 && !sockerr_again() ) )
{
+ closesocket( jd->fd );
+ jd->fd = -1;
+
hide_login_progress_error( gc, "Error while reading from server" );
signoff( gc );
return FALSE;
@@ -197,6 +214,33 @@ static xt_status jabber_end_of_stream( struct xt_node *node, gpointer data )
return XT_ABORT;
}
+static xt_status jabber_pkt_features( struct xt_node *node, gpointer data )
+{
+ struct gaim_connection *gc = data;
+ struct jabber_data *jd = gc->proto_data;
+ struct xt_node *c;
+
+ c = xt_find_node( node->children, "starttls" );
+ if( c )
+ {
+ /*
+ jd->flags |= JFLAG_SUPPORTS_TLS;
+ if( xt_find_node( c->children, "required" ) )
+ jd->flags |= JFLAG_REQUIRES_TLS;
+ */
+ }
+
+ /* This flag is already set if we authenticated via SASL, so now
+ we can resume the session in the new stream. */
+ if( jd->flags & JFLAG_AUTHENTICATED )
+ {
+ if( !jabber_get_roster( gc ) )
+ return XT_ABORT;
+ }
+
+ return XT_HANDLED;
+}
+
static xt_status jabber_pkt_misc( struct xt_node *node, gpointer data )
{
printf( "Received unknown packet:\n" );
@@ -207,9 +251,10 @@ static xt_status jabber_pkt_misc( struct xt_node *node, gpointer data )
static const struct xt_handler_entry jabber_handlers[] = {
{ "stream:stream", "<root>", jabber_end_of_stream },
- { "iq", "stream:stream", jabber_pkt_iq },
{ "message", "stream:stream", jabber_pkt_message },
{ "presence", "stream:stream", jabber_pkt_presence },
+ { "iq", "stream:stream", jabber_pkt_iq },
+ { "stream:features", "stream:stream", jabber_pkt_features },
{ "mechanisms", "stream:features", sasl_pkt_mechanisms },
{ "challenge", "stream:stream", sasl_pkt_challenge },
{ "success", "stream:stream", sasl_pkt_result },
@@ -230,7 +275,8 @@ gboolean jabber_start_stream( struct gaim_connection *gc )
jd->xt = xt_new( gc );
jd->xt->handlers = (struct xt_handler_entry*) jabber_handlers;
- jd->r_inpa = b_input_add( jd->fd, GAIM_INPUT_READ, jabber_read_callback, gc );
+ if( jd->r_inpa <= 0 )
+ jd->r_inpa = b_input_add( jd->fd, GAIM_INPUT_READ, jabber_read_callback, gc );
greet = g_strdup_printf( "<?xml version='1.0' ?>"
"<stream:stream to=\"%s\" xmlns=\"jabber:client\" "
@@ -253,11 +299,14 @@ void jabber_end_stream( struct gaim_connection *gc )
{
char eos[] = "</stream:stream>";
struct xt_node *node;
- int st;
+ int st = 1;
- node = jabber_make_packet( "presence", "unavailable", NULL, NULL );
- st = jabber_write_packet( gc, node );
- xt_free_node( node );
+ if( gc->flags & OPT_LOGGED_IN )
+ {
+ node = jabber_make_packet( "presence", "unavailable", NULL, NULL );
+ st = jabber_write_packet( gc, node );
+ xt_free_node( node );
+ }
if( st )
jabber_write( gc, eos, strlen( eos ) );