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; } |