diff options
Diffstat (limited to 'protocols')
| -rw-r--r-- | protocols/jabber/jabber.c | 20 | ||||
| -rw-r--r-- | protocols/jabber/jabber.h | 16 | ||||
| -rw-r--r-- | protocols/jabber/jabber_util.c | 168 | ||||
| -rw-r--r-- | protocols/jabber/message.c | 10 | ||||
| -rw-r--r-- | protocols/jabber/presence.c | 63 | 
5 files changed, 174 insertions, 103 deletions
| diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 2ef76444..a60cd4aa 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -216,12 +216,12 @@ static int jabber_send_im( struct gaim_connection *gc, char *who, char *message,  	struct xt_node *node;  	int st; -	bud = jabber_buddy_by_jid( gc, who ); +	bud = jabber_buddy_by_jid( gc, who, 0 );  	node = xt_new_node( "body", message, NULL );  	node = jabber_make_packet( "message", "chat", bud ? bud->full_jid : who, node ); -	if( ( jd->flags & JFLAG_WANT_TYPING ) && bud && +	if( bud && ( jd->flags & JFLAG_WANT_TYPING ) &&  	    ( ( bud->flags & JBFLAG_DOES_XEP85 ) ||  	     !( bud->flags & JBFLAG_PROBED_XEP85 ) ) )  	{ @@ -265,20 +265,24 @@ static void jabber_get_info( struct gaim_connection *gc, char *who )  	struct jabber_buddy *bud;  	if( strchr( who, '/' ) ) -		bud = jabber_buddy_by_jid( gc, who ); +		bud = jabber_buddy_by_jid( gc, who, 0 );  	else -		bud = g_hash_table_lookup( jd->buddies, who ); +	{ +		char *s = jabber_normalize( who ); +		bud = g_hash_table_lookup( jd->buddies, s ); +		g_free( s ); +	}  	while( bud )  	{ -		serv_got_crap( gc, "Buddy %s/%s (%d) information:\nAway state: %s\nAway message: %s", -		                   bud->handle, bud->resource, bud->priority, +		serv_got_crap( gc, "Buddy %s (%d) information:\nAway state: %s\nAway message: %s", +		                   bud->full_jid, bud->priority,  		                   bud->away_state ? bud->away_state->full_name : "(none)",  		                   bud->away_message ? : "(none)" );  		bud = bud->next;  	} -	jabber_get_vcard( gc, bud ? bud->handle : who ); +	jabber_get_vcard( gc, bud ? bud->full_jid : who );  }  static void jabber_set_away( struct gaim_connection *gc, char *state_txt, char *message ) @@ -328,7 +332,7 @@ static int jabber_send_typing( struct gaim_connection *gc, char *who, int typing  	/* Enable typing notification related code from now. */  	jd->flags |= JFLAG_WANT_TYPING; -	if( ( bud = jabber_buddy_by_jid( gc, who ) ) == NULL ) +	if( ( bud = jabber_buddy_by_jid( gc, who, 0 ) ) == NULL )  	{  		/* Sending typing notifications to unknown buddies is  		   unsupported for now. Shouldn't be a problem, I think. */ diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index da9bfd52..628cb03a 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -49,7 +49,7 @@ typedef enum  	                                   sure it gets sent only once. */  	JBFLAG_DOES_XEP85 = 2,		/* Set this when the resource seems to support  	                                   XEP85 (typing notification shite). */ -} jabber_buddy_flag_t; +} jabber_buddy_flags_t;  struct jabber_data  { @@ -92,7 +92,7 @@ struct jabber_cache_entry  struct jabber_buddy  { -	char *handle; +	char *bare_jid;  	char *full_jid;  	char *resource; @@ -101,7 +101,7 @@ struct jabber_buddy  	char *away_message;  	time_t last_act; -	jabber_buddy_flag_t flags; +	jabber_buddy_flags_t flags;  	struct jabber_buddy *next;  }; @@ -159,8 +159,16 @@ void jabber_cache_clean( struct gaim_connection *gc );  const struct jabber_away_state *jabber_away_state_by_code( char *code );  const struct jabber_away_state *jabber_away_state_by_name( char *name );  void jabber_buddy_ask( struct gaim_connection *gc, char *handle ); +char *jabber_normalize( char *orig ); + +typedef enum +{ +	GET_BUDDY_CREAT = 1,	/* Try to create it, if necessary. */ +	GET_BUDDY_EXACT = 2,	/* Get an exact message (only makes sense with bare JIDs). */ +} get_buddy_flags_t; +  struct jabber_buddy *jabber_buddy_add( struct gaim_connection *gc, char *full_jid ); -struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid ); +struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid, get_buddy_flags_t flags );  int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid );  int jabber_buddy_remove_bare( struct gaim_connection *gc, char *bare_jid ); diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 07d7a2fd..7b1961e0 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -250,33 +250,63 @@ void jabber_buddy_ask( struct gaim_connection *gc, char *handle )  	g_free( buf );  } +/* Returns a new string. Don't leak it! */ +char *jabber_normalize( char *orig ) +{ +	int len, i; +	char *new; +	 +	len = strlen( orig ); +	new = g_new( char, len + 1 ); +	for( i = 0; i < len; i ++ ) +		new[i] = tolower( orig[i] ); +	 +	new[i] = 0; +	return new; +} +  /* Adds a buddy/resource to our list. Returns NULL if full_jid is not really a -   FULL jid or if we already have this buddy/resource. */ -struct jabber_buddy *jabber_buddy_add( struct gaim_connection *gc, char *full_jid ) +   FULL jid or if we already have this buddy/resource. XXX: No, great, actually +   buddies from transports don't (usually) have resources. So we'll really have +   to deal with that properly. Set their ->resource property to NULL. Do *NOT* +   allow to mix this stuff, though... */ +struct jabber_buddy *jabber_buddy_add( struct gaim_connection *gc, char *full_jid_ )  {  	struct jabber_data *jd = gc->proto_data;  	struct jabber_buddy *bud, *new, *bi; -	char *s; +	char *s, *full_jid; -	if( !( s = strchr( full_jid, '/' ) ) ) -		return NULL; +	full_jid = jabber_normalize( full_jid_ ); +	 +	if( ( s = strchr( full_jid, '/' ) ) ) +		*s = 0;  	new = g_new0( struct jabber_buddy, 1 ); -	*s = 0;  	if( ( bud = g_hash_table_lookup( jd->buddies, full_jid ) ) )  	{ -		new->handle = bud->handle; +		/* If this is a transport buddy or whatever, it can't have more +		   than one instance, so this is always wrong: */ +		if( s == NULL || bud->resource == NULL ) +		{ +			if( s ) *s = '/'; +			g_free( new ); +			g_free( full_jid ); +			return NULL; +		} +		 +		new->bare_jid = bud->bare_jid;  		/* We already have another resource for this buddy, add the  		   new one to the list. */  		for( bi = bud; bi; bi = bi->next )  		{ -			/* Check for dupes. Resource seem to be case sensitive. */ -			if( strcmp( bi->resource, s + 1 ) == 0 ) +			/* Check for dupes. */ +			if( g_strcasecmp( bi->resource, s + 1 ) == 0 )  			{  				*s = '/';  				g_free( new ); +				g_free( full_jid );  				return NULL;  			}  			/* Append the new item to the list. */ @@ -289,13 +319,22 @@ struct jabber_buddy *jabber_buddy_add( struct gaim_connection *gc, char *full_ji  	}  	else  	{ -		new->handle = g_strdup( full_jid ); -		g_hash_table_insert( jd->buddies, new->handle, new ); +		new->bare_jid = g_strdup( full_jid ); +		g_hash_table_insert( jd->buddies, new->bare_jid, new );  	} -	*s = '/'; -	new->full_jid = g_strdup( full_jid ); -	new->resource = strchr( new->full_jid, '/' ) + 1; +	if( s ) +	{ +		*s = '/'; +		new->full_jid = full_jid; +		new->resource = strchr( new->full_jid, '/' ) + 1; +	} +	else +	{ +		/* Let's waste some more bytes of RAM instead of to make +		   memory management a total disaster here.. */ +		new->full_jid = full_jid; +	}  	return new;  } @@ -303,26 +342,56 @@ struct jabber_buddy *jabber_buddy_add( struct gaim_connection *gc, char *full_ji  /* Finds a buddy from our structures. Can find both full- and bare JIDs. When     asked for a bare JID, it uses the "resource_select" setting to see which     resource to pick. */ -struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid ) +struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid_, get_buddy_flags_t flags )  {  	struct jabber_data *jd = gc->proto_data;  	struct jabber_buddy *bud; -	char *s; +	char *s, *jid; +	 +	jid = jabber_normalize( jid_ );  	if( ( s = strchr( jid, '/' ) ) )  	{  		*s = 0;  		if( ( bud = g_hash_table_lookup( jd->buddies, jid ) ) ) -			for( ; bud; bud = bud->next ) -				if( strcmp( bud->resource, s + 1 ) == 0 ) -					break; +		{ +			/* Is this one of those no-resource buddies? */ +			if( bud->resource == NULL ) +			{ +				bud = NULL; +			} +			else +			{ +				/* See if there's an exact match. */ +				for( ; bud; bud = bud->next ) +					if( g_strcasecmp( bud->resource, s + 1 ) == 0 ) +						break; +			} +		} +		 +		*s = '/'; +		if( bud == NULL && ( flags & GET_BUDDY_CREAT ) ) +			bud = jabber_buddy_add( gc, jid ); +		 +		g_free( jid ); +		return bud;  	}  	else  	{  		struct jabber_buddy *best_prio, *best_time;  		char *set; -		best_prio = best_time = bud = g_hash_table_lookup( jd->buddies, jid ); +		bud = g_hash_table_lookup( jd->buddies, jid ); +		 +		g_free( jid ); +		 +		/* An exact match, or only one option. */ +		if( bud == NULL ) +			return ( flags & GET_BUDDY_CREAT ) ? jabber_buddy_add( gc, jid ) : NULL; +		else if( ( bud->resource == NULL || bud->next == NULL ) ) +			return bud; +		 +		best_prio = best_time = bud;  		for( ; bud; bud = bud->next )  		{  			if( bud->priority > best_prio->priority ) @@ -338,42 +407,54 @@ struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid  		else /* if( strcmp( set, "priority" ) == 0 ) */  			return best_prio;  	} -	 -	*s = '/'; -	return bud;  }  /* Remove one specific full JID from our list. Use this when a buddy goes -   off-line (because (s)he can still be online from a different location. */ -int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid ) +   off-line (because (s)he can still be online from a different location. +   XXX: See above, we should accept bare JIDs too... */ +int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid_ )  {  	struct jabber_data *jd = gc->proto_data;  	struct jabber_buddy *bud, *prev, *bi; -	char *s; +	char *s, *full_jid; -	if( !( s = strchr( full_jid, '/' ) ) ) -		return 0; +	full_jid = jabber_normalize( full_jid_ ); +	 +	if( ( s = strchr( full_jid, '/' ) ) ) +		*s = 0; -	*s = 0;  	if( ( bud = g_hash_table_lookup( jd->buddies, full_jid ) ) )  	{  		/* If there's only one item in the list (and if the resource  		   matches), removing it is simple. (And the hash reference  		   should be removed too!) */ -		if( bud->next == NULL && strcmp( bud->resource, s + 1 ) == 0 ) +		if( bud->next == NULL && ( ( s == NULL || bud->resource == NULL ) || g_strcasecmp( bud->resource, s + 1 ) == 0 ) )  		{ -			g_hash_table_remove( jd->buddies, bud->handle ); -			g_free( bud->handle ); +			g_hash_table_remove( jd->buddies, bud->bare_jid ); +			g_free( bud->bare_jid );  			g_free( bud->full_jid );  			g_free( bud->away_message );  			g_free( bud ); +			 +			g_free( full_jid ); +			 +			return 1; +		} +		else if( s == NULL || bud->resource == NULL ) +		{ +			/* Tried to remove a bare JID while this JID does seem +			   to have resources... (Or the opposite.) *sigh* */ +			g_free( full_jid ); +			return 0;  		}  		else  		{  			for( bi = bud, prev = NULL; bi; bi = (prev=bi)->next ) -				if( strcmp( bi->resource, s + 1 ) == 0 ) +				if( g_strcasecmp( bi->resource, s + 1 ) == 0 )  					break; +			g_free( full_jid ); +			  			if( bi )  			{  				if( prev ) @@ -381,25 +462,23 @@ int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid )  				else  					/* The hash table should point at the second  					   item, because we're removing the first. */ -					g_hash_table_replace( jd->buddies, bi->handle, bi->next ); +					g_hash_table_replace( jd->buddies, bi->bare_jid, bi->next );  				g_free( bi->full_jid );  				g_free( bi->away_message );  				g_free( bi ); +				 +				return 1;  			}  			else  			{ -				*s = '/';  				return 0;  			}  		} -		 -		*s = '/'; -		return 1;  	}  	else  	{ -		*s = '/'; +		g_free( full_jid );  		return 0;  	}  } @@ -407,19 +486,22 @@ int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid )  /* Remove a buddy completely; removes all resources that belong to the     specified bare JID. Use this when removing someone from the contact     list, for example. */ -int jabber_buddy_remove_bare( struct gaim_connection *gc, char *bare_jid ) +int jabber_buddy_remove_bare( struct gaim_connection *gc, char *bare_jid_ )  {  	struct jabber_data *jd = gc->proto_data;  	struct jabber_buddy *bud, *next; +	char *bare_jid; -	if( strchr( bare_jid, '/' ) ) +	if( strchr( bare_jid_, '/' ) )  		return 0; +	bare_jid = jabber_normalize( bare_jid_ ); +	  	if( ( bud = g_hash_table_lookup( jd->buddies, bare_jid ) ) )  	{  		/* Most important: Remove the hash reference. We don't know  		   this buddy anymore. */ -		g_hash_table_remove( jd->buddies, bud->handle ); +		g_hash_table_remove( jd->buddies, bud->bare_jid );  		/* Deallocate the linked list of resources. */  		while( bud ) @@ -431,10 +513,12 @@ int jabber_buddy_remove_bare( struct gaim_connection *gc, char *bare_jid )  			bud = next;  		} +		g_free( bare_jid );  		return 1;  	}  	else  	{ +		g_free( bare_jid );  		return 0;  	}  } diff --git a/protocols/jabber/message.c b/protocols/jabber/message.c index ad19a1dc..ac72f661 100644 --- a/protocols/jabber/message.c +++ b/protocols/jabber/message.c @@ -46,7 +46,7 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data )  		if( ( s = strchr( from, '/' ) ) )  		{ -			if( ( bud = jabber_buddy_by_jid( gc, from ) ) ) +			if( ( bud = jabber_buddy_by_jid( gc, from, GET_BUDDY_EXACT ) ) )  				bud->last_act = time( NULL );  			else  				*s = 0; /* We need to generate a bare JID now. */ @@ -75,7 +75,7 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data )  			fullmsg = g_string_append( fullmsg, body->text );  		if( fullmsg->len > 0 ) -			serv_got_im( gc, bud ? bud->handle : from, fullmsg->str, 0, 0, fullmsg->len ); +			serv_got_im( gc, bud ? bud->bare_jid : from, fullmsg->str, 0, 0, fullmsg->len );  		g_string_free( fullmsg, TRUE ); @@ -83,18 +83,18 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data )  		if( xt_find_node( node->children, "composing" ) )  		{  			bud->flags |= JBFLAG_DOES_XEP85; -			serv_got_typing( gc, bud ? bud->handle : from, 0, 1 ); +			serv_got_typing( gc, bud ? bud->bare_jid : from, 0, 1 );  		}  		/* No need to send a "stopped typing" signal when there's a message. */  		else if( xt_find_node( node->children, "active" ) && ( body == NULL ) )  		{  			bud->flags |= JBFLAG_DOES_XEP85; -			serv_got_typing( gc, bud ? bud->handle : from, 0, 0 ); +			serv_got_typing( gc, bud ? bud->bare_jid : from, 0, 0 );  		}  		else if( xt_find_node( node->children, "paused" ) )  		{  			bud->flags |= JBFLAG_DOES_XEP85; -			serv_got_typing( gc, bud ? bud->handle : from, 0, 2 ); +			serv_got_typing( gc, bud ? bud->bare_jid : from, 0, 2 );  		}  		if( s ) diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c index ccd22f60..b56acb51 100644 --- a/protocols/jabber/presence.c +++ b/protocols/jabber/presence.c @@ -37,36 +37,12 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data )  	if( type == NULL )  	{ -		if( ( s = strchr( from, '/' ) ) == NULL ) +		if( !( bud = jabber_buddy_by_jid( gc, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) )  		{ -			char *s = xt_to_string( node ); -			serv_got_crap( gc, "WARNING: Ignoring presence tag with bare JID: %s", s ); -			g_free( s ); +			serv_got_crap( gc, "WARNING: Could not handle presence information from JID: %s", from );  			return XT_HANDLED;  		} -		if( !( bud = jabber_buddy_by_jid( gc, from ) ) ) -		{ -			/* FOR NOW, s still contains the location of the /. -			   Keep this in mind when changing things here. :-) */ -			 -			/* We check if the buddy is in the contact list, -			   because Jabber servers seem to like to send -			   presence information of buddies we removed -			   from our list sometimes, for example... */ -			 -			*s = 0; -			if( find_buddy( gc, from ) == NULL ) -			{ -				*s = '/'; -				serv_got_crap( gc, "WARNING: Ignoring presence information from unknown JID: %s", from ); -				return XT_HANDLED; -			} -			*s = '/'; -			 -			bud = jabber_buddy_add( gc, from ); -		} -		  		g_free( bud->away_message );  		if( ( c = xt_find_node( node->children, "status" ) ) && c->text_len > 0 )  			bud->away_message = g_strdup( c->text ); @@ -88,36 +64,34 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data )  		else  			bud->priority = 0; -		serv_got_update( gc, bud->handle, 1, 0, 0, 0, +		serv_got_update( gc, bud->bare_jid, 1, 0, 0, 0,  		                 bud->away_state ? UC_UNAVAILABLE : 0, 0 );  	}  	else if( strcmp( type, "unavailable" ) == 0 )  	{ -		char *s; -		 -		if( ( s = strchr( from, '/' ) ) == NULL ) -		{ -			char *s = xt_to_string( node ); -			serv_got_crap( gc, "WARNING: Ignoring presence tag with bare JID: %s\n", s ); -			g_free( s ); -			return XT_HANDLED; -		} -		 -		if( jabber_buddy_by_jid( gc, from ) == NULL ) +		if( jabber_buddy_by_jid( gc, from, GET_BUDDY_EXACT ) == NULL )  		{  			serv_got_crap( gc, "WARNING: Received presence information from unknown JID: %s", from );  			return XT_HANDLED;  		}  		jabber_buddy_remove( gc, from ); -		*s = 0; -		/* Only count this as offline if there's no other resource -		   available anymore. */ -		if( jabber_buddy_by_jid( gc, from ) == NULL ) -			serv_got_update( gc, from, 0, 0, 0, 0, 0, 0 ); +		if( ( s = strchr( from, '/' ) ) ) +		{ +			*s = 0; -		*s = '/'; +			/* Only count this as offline if there's no other resource +			   available anymore. */ +			if( jabber_buddy_by_jid( gc, from, 0 ) == NULL ) +				serv_got_update( gc, from, 0, 0, 0, 0, 0, 0 ); +			 +			*s = '/'; +		} +		else +		{ +			serv_got_update( gc, from, 0, 0, 0, 0, 0, 0 ); +		}  	}  	else if( strcmp( type, "subscribe" ) == 0 )  	{ @@ -125,6 +99,7 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data )  	}  	else if( strcmp( type, "subscribed" ) == 0 )  	{ +		/* Not sure about this one, actually... */  		serv_got_crap( gc, "%s just accepted your authorization request", from );  	}  	else if( strcmp( type, "unsubscribe" ) == 0 || strcmp( type, "unsubscribed" ) == 0 ) | 
