diff options
author | Wilmer van der Gaast <wilmer@gaast.net> | 2006-09-22 18:56:58 +0200 |
---|---|---|
committer | Wilmer van der Gaast <wilmer@gaast.net> | 2006-09-22 18:56:58 +0200 |
commit | 8d7429102adf8dce6844f2f3da2723d1f87c6442 (patch) | |
tree | 78a178e4798f8f11ac5590137efc0642aeea6378 /protocols/jabber/io.c | |
parent | 59974884ba72d6e8fa008d07ee93bd228d30a99c (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.c | 67 |
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 ) ); |