diff options
Diffstat (limited to 'protocols/jabber/iq.c')
| -rw-r--r-- | protocols/jabber/iq.c | 274 | 
1 files changed, 149 insertions, 125 deletions
| 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; | 
