diff options
| -rw-r--r-- | protocols/jabber/jabber.c | 16 | ||||
| -rw-r--r-- | protocols/jabber/jabber.h | 19 | ||||
| -rw-r--r-- | protocols/jabber/jabber_util.c | 132 | ||||
| -rw-r--r-- | protocols/jabber/presence.c | 59 | 
4 files changed, 212 insertions, 14 deletions
| diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index b508cb45..266022ba 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -79,6 +79,7 @@ static void jabber_login( account_t *acc )  	jd->server ++;  	jd->node_cache = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, jabber_cache_entry_free ); +	jd->buddies = g_hash_table_new( g_str_hash, g_str_equal );  	/* Figure out the hostname to connect to. */  	if( acc->server ) @@ -168,10 +169,23 @@ static GList *jabber_away_states( struct gaim_connection *gc )  static void jabber_get_info( struct gaim_connection *gc, char *who )  { +	struct jabber_buddy *bud;  	struct xt_node *node; +	bud = jabber_buddy_by_jid( gc, who ); +	while( bud ) +	{ +		serv_got_crap( gc, "Buddy %s/%s (%d) information:\nAway state: %s\nAway message: %s", +		                   bud->handle, bud->resource, bud->priority, +		                   bud->away_state ? bud->away_state->full_name : "(none)", +		                   bud->away_message ? : "(none)" ); +		bud = bud->next; +	} +	 +//	node = xt_new_node( "vCard", NULL, NULL ); +//	xt_add_attr( node, "xmlns", "vcard-temp" );  	node = xt_new_node( "query", NULL, NULL ); -	xt_add_attr( node, "xmlns", "http://jabber.org/protocol/disco#info" ); +	xt_add_attr( node, "xmlns", "jabber:iq:version" );  	node = jabber_make_packet( "iq", "get", who, node );  	// jabber_cache_add( gc, node,  ); diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 6791a0f5..450c8be7 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -60,6 +60,7 @@ struct jabber_data  	char *away_message;  	GHashTable *node_cache; +	GHashTable *buddies;  };  struct jabber_away_state @@ -76,6 +77,21 @@ struct jabber_cache_entry  	jabber_cache_event func;  }; +struct jabber_buddy +{ +	char *handle; +	char *resource; +	 +	int priority; +	struct jabber_away_state *away_state; +	char *away_message; +	 +	time_t last_act; +	int flags; +	 +	struct jabber_buddy *next; +}; +  /* iq.c */  xt_status jabber_pkt_iq( struct xt_node *node, gpointer data );  int jabber_init_iq_auth( struct gaim_connection *gc ); @@ -103,6 +119,9 @@ 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 ); +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 ); +int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid );  extern const struct jabber_away_state jabber_away_state_list[]; diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index f26b9617..f4cd40d4 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -201,3 +201,135 @@ void jabber_buddy_ask( struct gaim_connection *gc, char *handle )  	do_ask_dialog( gc, buf, bla, jabber_buddy_ask_yes, jabber_buddy_ask_no );  	g_free( buf );  } + +/* 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 ) +{ +	struct jabber_data *jd = gc->proto_data; +	struct jabber_buddy *bud, *new, *bi; +	char *s; +	 +	if( !( s = strchr( full_jid, '/' ) ) ) +		return NULL; +	 +	new = g_new0( struct jabber_buddy, 1 ); +	 +	*s = 0; +	if( ( bud = g_hash_table_lookup( jd->buddies, full_jid ) ) ) +	{ +		new->handle = bud->handle; +		 +		/* 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 ) +			{ +				*s = '/'; +				g_free( new ); +				return NULL; +			} +			/* Append the new item to the list. */ +			else if( bi->next == NULL ) +			{ +				bi->next = new; +				break; +			} +		} +	} +	else +	{ +		new->handle = g_strdup( full_jid ); +		g_hash_table_insert( jd->buddies, new->handle, new ); +	} +	 +	*s = '/'; +	new->resource = g_strdup( s + 1 ); +	 +	return new; +} + +struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid ) +{ +	struct jabber_data *jd = gc->proto_data; +	struct jabber_buddy *bud; +	char *s; +	 +	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; +	} +	else +	{ +		/* TODO: Add selection. */ +		return g_hash_table_lookup( jd->buddies, jid ); +	} +	 +	*s = '/'; +	return bud; +} + +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; +	 +	if( !( s = strchr( full_jid, '/' ) ) ) +		return 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 ) +		{ +			g_hash_table_remove( jd->buddies, bud->handle ); +			g_free( bud->handle ); +			g_free( bud->resource ); +			g_free( bud->away_message ); +			g_free( bud ); +		} +		else +		{ +			for( bi = bud, prev = NULL; bi; bi = (prev=bi)->next ) +				if( strcmp( bi->resource, s + 1 ) == 0 ) +					break; +			 +			if( bi ) +			{ +				if( prev ) +					prev->next = bi->next; +				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_free( bi->resource ); +				g_free( bi->away_message ); +				g_free( bi ); +			} +			else +			{ +				*s = '/'; +				return 0; +			} +		} +		 +		*s = '/'; +		return 1; +	} +	else +	{ +		*s = '/'; +		return 0; +	} +} diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c index 5bef498d..86bdcb1d 100644 --- a/protocols/jabber/presence.c +++ b/protocols/jabber/presence.c @@ -28,26 +28,62 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data )  	struct gaim_connection *gc = data;  	char *from = xt_find_attr( node, "from" );  	char *type = xt_find_attr( node, "type" );	/* NULL should mean the person is online. */ -	char *s; +	struct xt_node *c;  	if( !from )  		return XT_HANDLED; -	s = strchr( from, '/' ); -	if( s ) -		*s = 0; -	 -	/* Will implement better parsing of away states/msgs when we -	   finally do those API changes. Which will probably be after -	   merging this module into the main tree. */  	if( type == NULL ) -		serv_got_update( gc, from, 1, 0, 0, 0, 0, 0 ); +	{ +		struct jabber_buddy *bud; +		 +		if( !( bud = jabber_buddy_by_jid( gc, from ) ) ) +		{ +			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 ); +		else +			bud->away_message = NULL; +		 +		if( ( c = xt_find_node( node->children, "show" ) ) && c->text_len > 0 ) +			bud->away_state = (void*) jabber_away_state_by_code( c->text ); +		else +			bud->away_state = NULL; +		 +		if( ( c = xt_find_node( node->children, "priority" ) ) && c->text_len > 0 ) +			bud->priority = atoi( c->text ); +		else +			bud->priority = 0; +		 +		serv_got_update( gc, bud->handle, 1, 0, 0, 0, 0, 0 ); +	}  	else if( strcmp( type, "unavailable" ) == 0 ) -		serv_got_update( gc, from, 0, 0, 0, 0, 0, 0 ); +	{ +		char *s; +		 +		jabber_buddy_remove( gc, from ); +		 +		if( ( s = strchr( 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 ); +		 +		*s = '/'; +	}  	else if( strcmp( type, "subscribe" ) == 0 ) +	{  		jabber_buddy_ask( gc, from ); +	}  	else if( strcmp( type, "subscribed" ) == 0 ) +	{  		serv_got_crap( gc, "%s just accepted your authorization request", from ); +	}  	else if( strcmp( type, "unsubscribe" ) == 0 || strcmp( type, "unsubscribed" ) == 0 )  	{  		/* Do nothing here. Plenty of control freaks or over-curious @@ -69,9 +105,6 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data )  		xt_print( node );  	} -	if( s ) -		*s = '/'; -	  	return XT_HANDLED;  } | 
