diff options
| -rw-r--r-- | protocols/jabber/io.c | 67 | ||||
| -rw-r--r-- | protocols/jabber/iq.c | 2 | ||||
| -rw-r--r-- | protocols/jabber/jabber.h | 4 | ||||
| -rw-r--r-- | protocols/jabber/sasl.c | 20 | ||||
| -rw-r--r-- | protocols/nogaim.c | 5 | 
5 files changed, 86 insertions, 12 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 ) ); diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index 119176f9..bcce5289 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -129,7 +129,7 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )  	return XT_HANDLED;  } -int jabber_start_auth( struct gaim_connection *gc ) +int jabber_start_iq_auth( struct gaim_connection *gc )  {  	struct jabber_data *jd = gc->proto_data;  	struct xt_node *node; diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 03fe57a7..f8b604b0 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -34,12 +34,11 @@ typedef enum  	JFLAG_STREAM_STARTED = 1,	/* Set when we detected the beginning of the stream and want to do auth. */  	JFLAG_AUTHENTICATED = 2,	/* Set when we're successfully authenticatd. */  	JFLAG_STREAM_RESTART = 4,	/* Set when we want to restart the stream (after SASL or TLS). */ -	JFLAG_SUPPORTS_TLS = 8,		/* Set when there's <starttls/> in <stream:features>. */  } jabber_flags_t;  /* iq.c */  xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ); -int jabber_start_auth( struct gaim_connection *gc ); +int jabber_start_iq_auth( struct gaim_connection *gc );  int jabber_get_roster( struct gaim_connection *gc );  xt_status jabber_pkt_message( struct xt_node *node, gpointer data ); @@ -65,6 +64,7 @@ void jabber_end_stream( struct gaim_connection *gc );  xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data );  xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data );  xt_status sasl_pkt_result( struct xt_node *node, gpointer data ); +gboolean sasl_supported( struct gaim_connection *gc );  struct jabber_data  { diff --git a/protocols/jabber/sasl.c b/protocols/jabber/sasl.c index da577877..2f75e733 100644 --- a/protocols/jabber/sasl.c +++ b/protocols/jabber/sasl.c @@ -34,6 +34,15 @@ xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data )  	char *s;  	int sup_plain = 0, sup_digest = 0; +	if( !sasl_supported( gc ) ) +	{ +		/* Should abort this now, since we should already be doing +		   IQ authentication. Strange things happen when you try +		   to do both... */ +		serv_got_crap( gc, "XMPP 1.0 non-compliant server seems to support SASL, please report this as a BitlBee bug!" ); +		return XT_HANDLED; +	} +	  	s = xt_find_attr( node, "xmlns" );  	if( !s || strcmp( s, SASL_NS ) != 0 )  	{ @@ -93,6 +102,7 @@ xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data )  xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data )  { +	return XT_HANDLED;  }  xt_status sasl_pkt_result( struct xt_node *node, gpointer data ) @@ -122,3 +132,13 @@ xt_status sasl_pkt_result( struct xt_node *node, gpointer data )  	return XT_HANDLED;  } + +/* This one is needed to judge if we'll do authentication using IQ or SASL. +   It's done by checking if the <stream:stream> from the server has a +   version attribute. I don't know if this is the right way though... */ +gboolean sasl_supported( struct gaim_connection *gc ) +{ +	struct jabber_data *jd = gc->proto_data; +	 +	return ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) != NULL; +} diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 47e2bda6..ec87ccd5 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -279,6 +279,11 @@ void signoff( struct gaim_connection *gc )  	user_t *t, *u = irc->users;  	account_t *a; +	/* Nested calls might happen sometimes, this is probably the best +	   place to catch them. */ +	if( gc->flags & OPT_LOGGING_OUT ) +		return; +	  	serv_got_crap( gc, "Signing off.." );  	b_event_remove( gc->keepalive ); | 
