aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;
}