diff options
| author | Wilmer van der Gaast <wilmer@gaast.net> | 2006-10-08 20:41:11 +0200 | 
|---|---|---|
| committer | Wilmer van der Gaast <wilmer@gaast.net> | 2006-10-08 20:41:11 +0200 | 
| commit | 861c199fb60fecf5dab96e0ed9d4b0cf0c57822f (patch) | |
| tree | 45a66a0ebd0f1d1d25016490f00471c7a3456927 /protocols | |
| parent | 038d17f834219505cbbdae469b2b150117467dd0 (diff) | |
Moved handling of all IQ packets to event handlers. Cleaned up a LOT of
mess in iq.c!
Diffstat (limited to 'protocols')
| -rw-r--r-- | protocols/jabber/io.c | 8 | ||||
| -rw-r--r-- | protocols/jabber/iq.c | 274 | ||||
| -rw-r--r-- | protocols/jabber/jabber.c | 2 | ||||
| -rw-r--r-- | protocols/jabber/jabber.h | 7 | ||||
| -rw-r--r-- | protocols/jabber/jabber_util.c | 16 | 
5 files changed, 165 insertions, 142 deletions
| diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c index c6ad68e0..783d6d2c 100644 --- a/protocols/jabber/io.c +++ b/protocols/jabber/io.c @@ -213,7 +213,7 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition  					}  					else  					{ -						return jabber_start_iq_auth( gc ); +						return jabber_init_iq_auth( gc );  					}  				}  			} @@ -350,7 +350,7 @@ static xt_status jabber_pkt_features( struct xt_node *node, gpointer data )  	   to be XMPP 1.0 compliant! */  	else if( !( jd->flags & JFLAG_AUTHENTICATED ) && sasl_supported( gc ) )  	{ -		if( !jabber_start_iq_auth( gc ) ) +		if( !jabber_init_iq_auth( gc ) )  			return XT_ABORT;  	} @@ -359,7 +359,7 @@ static xt_status jabber_pkt_features( struct xt_node *node, gpointer data )  		reply = xt_new_node( "bind", NULL, xt_new_node( "resource", set_getstr( &gc->acc->set, "resource" ), NULL ) );  		xt_add_attr( reply, "xmlns", "urn:ietf:params:xml:ns:xmpp-bind" );  		reply = jabber_make_packet( "iq", "set", NULL, reply ); -		jabber_cache_add( gc, reply ); +		jabber_cache_add( gc, reply, jabber_pkt_bind_sess );  		if( !jabber_write_packet( gc, reply ) )  			return XT_ABORT; @@ -372,7 +372,7 @@ static xt_status jabber_pkt_features( struct xt_node *node, gpointer data )  		reply = xt_new_node( "session", NULL, NULL );  		xt_add_attr( reply, "xmlns", "urn:ietf:params:xml:ns:xmpp-session" );  		reply = jabber_make_packet( "iq", "set", NULL, reply ); -		jabber_cache_add( gc, reply ); +		jabber_cache_add( gc, reply, jabber_pkt_bind_sess );  		if( !jabber_write_packet( gc, reply ) )  			return XT_ABORT; diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index ae4ed099..1b968739 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -27,161 +27,161 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )  {  	struct gaim_connection *gc = data;  	struct jabber_data *jd = gc->proto_data; -	struct xt_node *query, *reply = NULL, *orig = NULL, *c; -	char *s, *type, *xmlns; -	int st; +	char *type, *s; -	query = xt_find_node( node->children, "query" );  	type = xt_find_attr( node, "type" );  	if( !type ) -		return XT_HANDLED;	/* Ignore it for now, don't know what's best... */ +	{ +		hide_login_progress_error( gc, "Received IQ packet without type!" ); +		signoff( gc ); +		return XT_ABORT; +	} +	 +	if( ( s = xt_find_attr( node, "id" ) ) && +	    ( strcmp( type, "result" ) == 0 || strcmp( type, "error" ) == 0 ) ) +	{ +		struct jabber_cache_entry *entry; +		 +		entry = g_hash_table_lookup( jd->node_cache, s ); +		 +		if( entry == NULL ) +			serv_got_crap( gc, "WARNING: Received IQ %s packet with unknown/expired ID %s!", type, s ); +		else if( entry->func ) +			return entry->func( gc, node, entry->node ); +	} +	 +	return XT_HANDLED; +} + +static xt_status jabber_do_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); +static xt_status jabber_finish_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); + +int jabber_init_iq_auth( struct gaim_connection *gc ) +{ +	struct jabber_data *jd = gc->proto_data; +	struct xt_node *node; +	int st; +	 +	node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) ); +	xt_add_attr( node, "xmlns", "jabber:iq:auth" ); +	node = jabber_make_packet( "iq", "get", NULL, node ); -	xmlns = xt_find_attr( query, "xmlns" ); +	jabber_cache_add( gc, node, jabber_do_iq_auth ); +	st = jabber_write_packet( gc, node ); -	if( ( s = xt_find_attr( node, "id" ) ) ) -		orig = jabber_cache_get( gc, s ); +	return st; +} + +static xt_status jabber_do_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) +{ +	struct jabber_data *jd = gc->proto_data; +	struct xt_node *reply, *query; +	xt_status st; +	char *s; -	if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:auth" ) == 0 ) +	query = xt_find_node( node->children, "query" ); +	 +	/* Time to authenticate ourselves! */ +	reply = xt_new_node( "query", NULL, NULL ); +	xt_add_attr( reply, "xmlns", "jabber:iq:auth" ); +	xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) ); +	xt_add_child( reply, xt_new_node( "resource", set_getstr( &gc->acc->set, "resource" ), NULL ) ); +	 +	if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) )  	{ -		/* Time to authenticate ourselves! */ -		reply = xt_new_node( "query", NULL, NULL ); -		xt_add_attr( reply, "xmlns", "jabber:iq:auth" ); -		xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) ); -		xt_add_child( reply, xt_new_node( "resource", set_getstr( &gc->acc->set, "resource" ), NULL ) ); +		/* We can do digest authentication, it seems, and of +		   course we prefer that. */ +		SHA_CTX sha; +		char hash_hex[40]; +		unsigned char hash[20]; +		int i; -		if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) ) -		{ -			/* We can do digest authentication, it seems, and of -			   course we prefer that. */ -			SHA_CTX sha; -			char hash_hex[40]; -			unsigned char hash[20]; -			int i; -			 -			shaInit( &sha ); -			shaUpdate( &sha, (unsigned char*) s, strlen( s ) ); -			shaUpdate( &sha, (unsigned char*) gc->acc->pass, strlen( gc->acc->pass ) ); -			shaFinal( &sha, hash ); -			 -			for( i = 0; i < 20; i ++ ) -				sprintf( hash_hex + i * 2, "%02x", hash[i] ); -			 -			xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) ); -		} -		else if( xt_find_node( query->children, "password" ) ) -		{ -			/* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */ -			xt_add_child( reply, xt_new_node( "password", gc->acc->pass, NULL ) ); -		} -		else -		{ -			xt_free_node( reply ); -			 -			hide_login_progress( gc, "Can't find suitable authentication method" ); -			signoff( gc ); -			return XT_ABORT; -		} +		shaInit( &sha ); +		shaUpdate( &sha, (unsigned char*) s, strlen( s ) ); +		shaUpdate( &sha, (unsigned char*) gc->acc->pass, strlen( gc->acc->pass ) ); +		shaFinal( &sha, hash ); -		reply = jabber_make_packet( "iq", "set", NULL, reply ); -		jabber_cache_add( gc, reply ); -		st = jabber_write_packet( gc, reply ); +		for( i = 0; i < 20; i ++ ) +			sprintf( hash_hex + i * 2, "%02x", hash[i] ); -		return st ? XT_HANDLED : XT_ABORT; +		xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) );  	} -	if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:roster" ) == 0 ) +	else if( xt_find_node( query->children, "password" ) )  	{ -		struct xt_node *node; -		 -		node = query->children; -		while( ( node = xt_find_node( node, "item" ) ) ) -		{ -			char *jid = xt_find_attr( node, "jid" ); -			char *name = xt_find_attr( node, "name" ); -			char *sub = xt_find_attr( node, "subscription" ); -			 -			if( jid && sub && ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) ) -				add_buddy( gc, NULL, jid, name ); -			 -			node = node->next; -		} -		 -		account_online( gc ); +		/* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */ +		xt_add_child( reply, xt_new_node( "password", gc->acc->pass, NULL ) );  	} -	else if( strcmp( type, "result" ) == 0 && orig ) +	else  	{ -		struct xt_node *c; +		xt_free_node( reply ); -		if( !( jd->flags & JFLAG_AUTHENTICATED ) && -		    ( c = xt_find_node( orig->children, "query" ) ) && -		    ( c = xt_find_node( c->children, "username" ) ) && -		    c->text_len ) -		{ -			/* This happens when we just successfully authenticated -			   the old (non-SASL) way. */ -			jd->flags |= JFLAG_AUTHENTICATED; -			if( !jabber_get_roster( gc ) ) -				return XT_ABORT; -		} -		/* Tricky: Look for <bind> in the reply, because the server -		   should confirm the chosen resource string there. For -		   <session>, however, look in the cache, because the server -		   will probably not include it in its reply. */ -		else if( ( c = xt_find_node( node->children, "bind" ) ) || -		         ( c = xt_find_node( orig->children, "session" ) ) ) -		{ -			if( strcmp( c->name, "bind" ) == 0 ) -			{ -				c = xt_find_node( c->children, "jid" ); -				if( c && c->text_len && ( s = strchr( c->text, '/' ) ) && -				    strcmp( s + 1, set_getstr( &gc->acc->set, "resource" ) ) != 0 ) -					serv_got_crap( gc, "Server changed session resource string to `%s'", s + 1 ); -				 -				jd->flags &= ~JFLAG_WAIT_BIND; -			} -			else if( strcmp( c->name, "session" ) == 0 ) -				jd->flags &= ~JFLAG_WAIT_SESSION; -			 -			if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 ) -			{ -				if( !jabber_get_roster( gc ) ) -					return XT_ABORT; -			} -		} +		hide_login_progress( gc, "Can't find suitable authentication method" ); +		signoff( gc ); +		return XT_ABORT;  	} -	else if( strcmp( type, "error" ) == 0 ) +	 +	reply = jabber_make_packet( "iq", "set", NULL, reply ); +	jabber_cache_add( gc, reply, jabber_finish_iq_auth ); +	st = jabber_write_packet( gc, reply ); +	 +	return st ? XT_HANDLED : XT_ABORT; +} + +static xt_status jabber_finish_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) +{ +	char *type = xt_find_attr( node, "type" ); +	struct jabber_data *jd = gc->proto_data; +	 +	if( strcmp( type, "error" ) == 0 ) +	{ +		hide_login_progress( gc, "Authentication failure" ); +		signoff( gc ); +		return XT_ABORT; +	} +	else if( strcmp( type, "result" ) == 0 )  	{ -		if( !( jd->flags & JFLAG_AUTHENTICATED ) && -		      orig && -		    ( c = xt_find_node( orig->children, "query" ) ) && -		    ( c = xt_find_node( c->children, "username" ) ) && -		    c->text_len ) -		{ -			hide_login_progress( gc, "Authentication failure" ); -			signoff( gc ); +		/* This happens when we just successfully authenticated the +		   old (non-SASL) way. */ +		jd->flags |= JFLAG_AUTHENTICATED; +		if( !jabber_get_roster( gc ) )  			return XT_ABORT; -		}  	}  	return XT_HANDLED;  } -int jabber_start_iq_auth( struct gaim_connection *gc ) +xt_status jabber_pkt_bind_sess( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig )  {  	struct jabber_data *jd = gc->proto_data; -	struct xt_node *node; -	int st; +	struct xt_node *c; +	char *s; -	node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) ); -	xt_add_attr( node, "xmlns", "jabber:iq:auth" ); -	node = jabber_make_packet( "iq", "get", NULL, node ); +	if( ( c = xt_find_node( node->children, "bind" ) ) ) +	{ +		c = xt_find_node( c->children, "jid" ); +		if( c && c->text_len && ( s = strchr( c->text, '/' ) ) && +		    strcmp( s + 1, set_getstr( &gc->acc->set, "resource" ) ) != 0 ) +			serv_got_crap( gc, "Server changed session resource string to `%s'", s + 1 ); +		 +		jd->flags &= ~JFLAG_WAIT_BIND; +	} +	else +	{ +		jd->flags &= ~JFLAG_WAIT_SESSION; +	} -	st = jabber_write_packet( gc, node ); +	if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 ) +	{ +		if( !jabber_get_roster( gc ) ) +			return XT_ABORT; +	} -	xt_free_node( node ); -	return st; +	return XT_HANDLED;  } +static xt_status jabber_parse_roster( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); +  int jabber_get_roster( struct gaim_connection *gc )  {  	struct xt_node *node; @@ -193,12 +193,36 @@ int jabber_get_roster( struct gaim_connection *gc )  	xt_add_attr( node, "xmlns", "jabber:iq:roster" );  	node = jabber_make_packet( "iq", "get", NULL, node ); +	jabber_cache_add( gc, node, jabber_parse_roster );  	st = jabber_write_packet( gc, node ); -	xt_free_node( node );  	return st;  } +static xt_status jabber_parse_roster( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) +{ +	struct xt_node *query, *c; +	 +	query = xt_find_node( node->children, "query" ); +	 +	c = query->children; +	while( ( c = xt_find_node( c, "item" ) ) ) +	{ +		char *jid = xt_find_attr( c, "jid" ); +		char *name = xt_find_attr( c, "name" ); +		char *sub = xt_find_attr( c, "subscription" ); +		 +		if( jid && sub && ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) ) +			add_buddy( gc, NULL, jid, name ); +		 +		c = c->next; +	} +	 +	account_online( gc ); +	 +	return XT_HANDLED; +} +  int jabber_add_to_roster( struct gaim_connection *gc, char *handle, char *name )  {  	struct xt_node *node; diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 32d1d99d..b508cb45 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -173,7 +173,7 @@ static void jabber_get_info( struct gaim_connection *gc, char *who )  	node = xt_new_node( "query", NULL, NULL );  	xt_add_attr( node, "xmlns", "http://jabber.org/protocol/disco#info" );  	node = jabber_make_packet( "iq", "get", who, node ); -	jabber_cache_add( gc, node ); +	// jabber_cache_add( gc, node,  );  	jabber_write_packet( gc, node );  } diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 58a81810..6791a0f5 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -68,7 +68,7 @@ struct jabber_away_state  	char *full_name;  }; -typedef xt_status (*jabber_cache_event) ( struct gaim_connection *gc, struct xt_node *packet ); +typedef xt_status (*jabber_cache_event) ( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig );  struct jabber_cache_entry  { @@ -78,7 +78,8 @@ struct jabber_cache_entry  /* iq.c */  xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ); -int jabber_start_iq_auth( struct gaim_connection *gc ); +int jabber_init_iq_auth( struct gaim_connection *gc ); +xt_status jabber_pkt_bind_sess( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig );  int jabber_get_roster( struct gaim_connection *gc );  int jabber_add_to_roster( struct gaim_connection *gc, char *handle, char *name );  int jabber_remove_from_roster( struct gaim_connection *gc, char *handle ); @@ -95,7 +96,7 @@ int presence_send_request( struct gaim_connection *gc, char *handle, char *reque  char *set_eval_priority( set_t *set, char *value );  char *set_eval_tls( set_t *set, char *value );  struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children ); -void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node ); +void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node, jabber_cache_event func );  struct xt_node *jabber_cache_get( struct gaim_connection *gc, char *id );  void jabber_cache_entry_free( gpointer entry );  void jabber_cache_clean( struct gaim_connection *gc ); diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 11156258..f26b9617 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -81,7 +81,7 @@ struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_  /* Cache a node/packet for later use. Mainly useful for IQ packets if you need     them when you receive the response. Use this BEFORE sending the packet so     it'll get an id= tag, and do NOT free() the packet after writing it! */ -void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node ) +void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node, jabber_cache_event func )  {  	struct jabber_data *jd = gc->proto_data;  	char *id = g_strdup_printf( "BeeX%04x", next_id++ ); @@ -91,17 +91,10 @@ void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node )  	g_free( id );  	entry->node = node; +	entry->func = func;  	g_hash_table_insert( jd->node_cache, xt_find_attr( node, "id" ), entry );  } -struct xt_node *jabber_cache_get( struct gaim_connection *gc, char *id ) -{ -	struct jabber_data *jd = gc->proto_data; -	struct jabber_cache_entry *entry = g_hash_table_lookup( jd->node_cache, id ); -	 -	return entry ? entry->node : NULL; -} -  void jabber_cache_entry_free( gpointer data )  {  	struct jabber_cache_entry *entry = data; @@ -112,6 +105,11 @@ void jabber_cache_entry_free( gpointer data )  gboolean jabber_cache_clean_entry( gpointer key, gpointer entry, gpointer nullpointer ); +/* This one should be called from time to time (from keepalive, in this case) +   to make sure things don't stay in the node cache forever. By marking nodes +   during the first run and deleting marked nodes during a next run, every +   node should be available in the cache for at least a minute (assuming the +   function is indeed called every minute). */  void jabber_cache_clean( struct gaim_connection *gc )  {  	struct jabber_data *jd = gc->proto_data; | 
