aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/jabber
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2006-10-09 20:19:05 +0200
committerWilmer van der Gaast <wilmer@gaast.net>2006-10-09 20:19:05 +0200
commit6a1128d1333cf79f1ef9fb1f55b1b8fec67caf2a (patch)
tree7942fe056dfecb513fad0fb106011c890d9588ac /protocols/jabber
parent861c199fb60fecf5dab96e0ed9d4b0cf0c57822f (diff)
The module now keeps track of all resources available for a buddy. This
means the buddy won't show up offline when one resource goes down (while there are still others available). It also remembers away state information for every separate resource. Later this system will be used to keep track of client capability information (Typing notices, yay...) and who knows what else.
Diffstat (limited to 'protocols/jabber')
-rw-r--r--protocols/jabber/jabber.c16
-rw-r--r--protocols/jabber/jabber.h19
-rw-r--r--protocols/jabber/jabber_util.c132
-rw-r--r--protocols/jabber/presence.c59
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;
}