diff options
author | Wilmer van der Gaast <wilmer@gaast.net> | 2006-10-08 20:41:11 +0200 |
---|---|---|
committer | Wilmer van der Gaast <wilmer@gaast.net> | 2006-10-08 20:41:11 +0200 |
commit | 861c199fb60fecf5dab96e0ed9d4b0cf0c57822f (patch) | |
tree | 45a66a0ebd0f1d1d25016490f00471c7a3456927 | |
parent | 038d17f834219505cbbdae469b2b150117467dd0 (diff) |
Moved handling of all IQ packets to event handlers. Cleaned up a LOT of
mess in iq.c!
-rw-r--r-- | protocols/jabber/io.c | 8 | ||||
-rw-r--r-- | protocols/jabber/iq.c | 274 | ||||
-rw-r--r-- | protocols/jabber/jabber.c | 2 | ||||
-rw-r--r-- | protocols/jabber/jabber.h | 7 | ||||
-rw-r--r-- | protocols/jabber/jabber_util.c | 16 |
5 files changed, 165 insertions, 142 deletions
diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c index c6ad68e0..783d6d2c 100644 --- a/protocols/jabber/io.c +++ b/protocols/jabber/io.c @@ -213,7 +213,7 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition } else { - return jabber_start_iq_auth( gc ); + return jabber_init_iq_auth( gc ); } } } @@ -350,7 +350,7 @@ static xt_status jabber_pkt_features( struct xt_node *node, gpointer data ) to be XMPP 1.0 compliant! */ else if( !( jd->flags & JFLAG_AUTHENTICATED ) && sasl_supported( gc ) ) { - if( !jabber_start_iq_auth( gc ) ) + if( !jabber_init_iq_auth( gc ) ) return XT_ABORT; } @@ -359,7 +359,7 @@ static xt_status jabber_pkt_features( struct xt_node *node, gpointer data ) reply = xt_new_node( "bind", NULL, xt_new_node( "resource", set_getstr( &gc->acc->set, "resource" ), NULL ) ); xt_add_attr( reply, "xmlns", "urn:ietf:params:xml:ns:xmpp-bind" ); reply = jabber_make_packet( "iq", "set", NULL, reply ); - jabber_cache_add( gc, reply ); + jabber_cache_add( gc, reply, jabber_pkt_bind_sess ); if( !jabber_write_packet( gc, reply ) ) return XT_ABORT; @@ -372,7 +372,7 @@ static xt_status jabber_pkt_features( struct xt_node *node, gpointer data ) reply = xt_new_node( "session", NULL, NULL ); xt_add_attr( reply, "xmlns", "urn:ietf:params:xml:ns:xmpp-session" ); reply = jabber_make_packet( "iq", "set", NULL, reply ); - jabber_cache_add( gc, reply ); + jabber_cache_add( gc, reply, jabber_pkt_bind_sess ); if( !jabber_write_packet( gc, reply ) ) return XT_ABORT; diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index ae4ed099..1b968739 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -27,161 +27,161 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) { struct gaim_connection *gc = data; struct jabber_data *jd = gc->proto_data; - struct xt_node *query, *reply = NULL, *orig = NULL, *c; - char *s, *type, *xmlns; - int st; + char *type, *s; - query = xt_find_node( node->children, "query" ); type = xt_find_attr( node, "type" ); if( !type ) - return XT_HANDLED; /* Ignore it for now, don't know what's best... */ + { + hide_login_progress_error( gc, "Received IQ packet without type!" ); + signoff( gc ); + return XT_ABORT; + } + + if( ( s = xt_find_attr( node, "id" ) ) && + ( strcmp( type, "result" ) == 0 || strcmp( type, "error" ) == 0 ) ) + { + struct jabber_cache_entry *entry; + + entry = g_hash_table_lookup( jd->node_cache, s ); + + if( entry == NULL ) + serv_got_crap( gc, "WARNING: Received IQ %s packet with unknown/expired ID %s!", type, s ); + else if( entry->func ) + return entry->func( gc, node, entry->node ); + } + + return XT_HANDLED; +} + +static xt_status jabber_do_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); +static xt_status jabber_finish_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); + +int jabber_init_iq_auth( struct gaim_connection *gc ) +{ + struct jabber_data *jd = gc->proto_data; + struct xt_node *node; + int st; + + node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) ); + xt_add_attr( node, "xmlns", "jabber:iq:auth" ); + node = jabber_make_packet( "iq", "get", NULL, node ); - xmlns = xt_find_attr( query, "xmlns" ); + jabber_cache_add( gc, node, jabber_do_iq_auth ); + st = jabber_write_packet( gc, node ); - if( ( s = xt_find_attr( node, "id" ) ) ) - orig = jabber_cache_get( gc, s ); + return st; +} + +static xt_status jabber_do_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) +{ + struct jabber_data *jd = gc->proto_data; + struct xt_node *reply, *query; + xt_status st; + char *s; - if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:auth" ) == 0 ) + query = xt_find_node( node->children, "query" ); + + /* Time to authenticate ourselves! */ + reply = xt_new_node( "query", NULL, NULL ); + xt_add_attr( reply, "xmlns", "jabber:iq:auth" ); + xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) ); + xt_add_child( reply, xt_new_node( "resource", set_getstr( &gc->acc->set, "resource" ), NULL ) ); + + if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) ) { - /* Time to authenticate ourselves! */ - reply = xt_new_node( "query", NULL, NULL ); - xt_add_attr( reply, "xmlns", "jabber:iq:auth" ); - xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) ); - xt_add_child( reply, xt_new_node( "resource", set_getstr( &gc->acc->set, "resource" ), NULL ) ); + /* We can do digest authentication, it seems, and of + course we prefer that. */ + SHA_CTX sha; + char hash_hex[40]; + unsigned char hash[20]; + int i; - if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) ) - { - /* We can do digest authentication, it seems, and of - course we prefer that. */ - SHA_CTX sha; - char hash_hex[40]; - unsigned char hash[20]; - int i; - - shaInit( &sha ); - shaUpdate( &sha, (unsigned char*) s, strlen( s ) ); - shaUpdate( &sha, (unsigned char*) gc->acc->pass, strlen( gc->acc->pass ) ); - shaFinal( &sha, hash ); - - for( i = 0; i < 20; i ++ ) - sprintf( hash_hex + i * 2, "%02x", hash[i] ); - - xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) ); - } - else if( xt_find_node( query->children, "password" ) ) - { - /* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */ - xt_add_child( reply, xt_new_node( "password", gc->acc->pass, NULL ) ); - } - else - { - xt_free_node( reply ); - - hide_login_progress( gc, "Can't find suitable authentication method" ); - signoff( gc ); - return XT_ABORT; - } + shaInit( &sha ); + shaUpdate( &sha, (unsigned char*) s, strlen( s ) ); + shaUpdate( &sha, (unsigned char*) gc->acc->pass, strlen( gc->acc->pass ) ); + shaFinal( &sha, hash ); - reply = jabber_make_packet( "iq", "set", NULL, reply ); - jabber_cache_add( gc, reply ); - st = jabber_write_packet( gc, reply ); + for( i = 0; i < 20; i ++ ) + sprintf( hash_hex + i * 2, "%02x", hash[i] ); - return st ? XT_HANDLED : XT_ABORT; + xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) ); } - if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:roster" ) == 0 ) + else if( xt_find_node( query->children, "password" ) ) { - struct xt_node *node; - - node = query->children; - while( ( node = xt_find_node( node, "item" ) ) ) - { - char *jid = xt_find_attr( node, "jid" ); - char *name = xt_find_attr( node, "name" ); - char *sub = xt_find_attr( node, "subscription" ); - - if( jid && sub && ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) ) - add_buddy( gc, NULL, jid, name ); - - node = node->next; - } - - account_online( gc ); + /* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */ + xt_add_child( reply, xt_new_node( "password", gc->acc->pass, NULL ) ); } - else if( strcmp( type, "result" ) == 0 && orig ) + else { - struct xt_node *c; + xt_free_node( reply ); - if( !( jd->flags & JFLAG_AUTHENTICATED ) && - ( c = xt_find_node( orig->children, "query" ) ) && - ( c = xt_find_node( c->children, "username" ) ) && - c->text_len ) - { - /* This happens when we just successfully authenticated - the old (non-SASL) way. */ - jd->flags |= JFLAG_AUTHENTICATED; - if( !jabber_get_roster( gc ) ) - return XT_ABORT; - } - /* Tricky: Look for <bind> in the reply, because the server - should confirm the chosen resource string there. For - <session>, however, look in the cache, because the server - will probably not include it in its reply. */ - else if( ( c = xt_find_node( node->children, "bind" ) ) || - ( c = xt_find_node( orig->children, "session" ) ) ) - { - if( strcmp( c->name, "bind" ) == 0 ) - { - c = xt_find_node( c->children, "jid" ); - if( c && c->text_len && ( s = strchr( c->text, '/' ) ) && - strcmp( s + 1, set_getstr( &gc->acc->set, "resource" ) ) != 0 ) - serv_got_crap( gc, "Server changed session resource string to `%s'", s + 1 ); - - jd->flags &= ~JFLAG_WAIT_BIND; - } - else if( strcmp( c->name, "session" ) == 0 ) - jd->flags &= ~JFLAG_WAIT_SESSION; - - if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 ) - { - if( !jabber_get_roster( gc ) ) - return XT_ABORT; - } - } + hide_login_progress( gc, "Can't find suitable authentication method" ); + signoff( gc ); + return XT_ABORT; } - else if( strcmp( type, "error" ) == 0 ) + + reply = jabber_make_packet( "iq", "set", NULL, reply ); + jabber_cache_add( gc, reply, jabber_finish_iq_auth ); + st = jabber_write_packet( gc, reply ); + + return st ? XT_HANDLED : XT_ABORT; +} + +static xt_status jabber_finish_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) +{ + char *type = xt_find_attr( node, "type" ); + struct jabber_data *jd = gc->proto_data; + + if( strcmp( type, "error" ) == 0 ) + { + hide_login_progress( gc, "Authentication failure" ); + signoff( gc ); + return XT_ABORT; + } + else if( strcmp( type, "result" ) == 0 ) { - if( !( jd->flags & JFLAG_AUTHENTICATED ) && - orig && - ( c = xt_find_node( orig->children, "query" ) ) && - ( c = xt_find_node( c->children, "username" ) ) && - c->text_len ) - { - hide_login_progress( gc, "Authentication failure" ); - signoff( gc ); + /* This happens when we just successfully authenticated the + old (non-SASL) way. */ + jd->flags |= JFLAG_AUTHENTICATED; + if( !jabber_get_roster( gc ) ) return XT_ABORT; - } } return XT_HANDLED; } -int jabber_start_iq_auth( struct gaim_connection *gc ) +xt_status jabber_pkt_bind_sess( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) { struct jabber_data *jd = gc->proto_data; - struct xt_node *node; - int st; + struct xt_node *c; + char *s; - node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) ); - xt_add_attr( node, "xmlns", "jabber:iq:auth" ); - node = jabber_make_packet( "iq", "get", NULL, node ); + if( ( c = xt_find_node( node->children, "bind" ) ) ) + { + c = xt_find_node( c->children, "jid" ); + if( c && c->text_len && ( s = strchr( c->text, '/' ) ) && + strcmp( s + 1, set_getstr( &gc->acc->set, "resource" ) ) != 0 ) + serv_got_crap( gc, "Server changed session resource string to `%s'", s + 1 ); + + jd->flags &= ~JFLAG_WAIT_BIND; + } + else + { + jd->flags &= ~JFLAG_WAIT_SESSION; + } - st = jabber_write_packet( gc, node ); + if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 ) + { + if( !jabber_get_roster( gc ) ) + return XT_ABORT; + } - xt_free_node( node ); - return st; + return XT_HANDLED; } +static xt_status jabber_parse_roster( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); + int jabber_get_roster( struct gaim_connection *gc ) { struct xt_node *node; @@ -193,12 +193,36 @@ int jabber_get_roster( struct gaim_connection *gc ) xt_add_attr( node, "xmlns", "jabber:iq:roster" ); node = jabber_make_packet( "iq", "get", NULL, node ); + jabber_cache_add( gc, node, jabber_parse_roster ); st = jabber_write_packet( gc, node ); - xt_free_node( node ); return st; } +static xt_status jabber_parse_roster( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ) +{ + struct xt_node *query, *c; + + query = xt_find_node( node->children, "query" ); + + c = query->children; + while( ( c = xt_find_node( c, "item" ) ) ) + { + char *jid = xt_find_attr( c, "jid" ); + char *name = xt_find_attr( c, "name" ); + char *sub = xt_find_attr( c, "subscription" ); + + if( jid && sub && ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) ) + add_buddy( gc, NULL, jid, name ); + + c = c->next; + } + + account_online( gc ); + + return XT_HANDLED; +} + int jabber_add_to_roster( struct gaim_connection *gc, char *handle, char *name ) { struct xt_node *node; diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 32d1d99d..b508cb45 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -173,7 +173,7 @@ static void jabber_get_info( struct gaim_connection *gc, char *who ) node = xt_new_node( "query", NULL, NULL ); xt_add_attr( node, "xmlns", "http://jabber.org/protocol/disco#info" ); node = jabber_make_packet( "iq", "get", who, node ); - jabber_cache_add( gc, node ); + // jabber_cache_add( gc, node, ); jabber_write_packet( gc, node ); } diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 58a81810..6791a0f5 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -68,7 +68,7 @@ struct jabber_away_state char *full_name; }; -typedef xt_status (*jabber_cache_event) ( struct gaim_connection *gc, struct xt_node *packet ); +typedef xt_status (*jabber_cache_event) ( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); struct jabber_cache_entry { @@ -78,7 +78,8 @@ struct jabber_cache_entry /* iq.c */ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ); -int jabber_start_iq_auth( struct gaim_connection *gc ); +int jabber_init_iq_auth( struct gaim_connection *gc ); +xt_status jabber_pkt_bind_sess( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig ); int jabber_get_roster( struct gaim_connection *gc ); int jabber_add_to_roster( struct gaim_connection *gc, char *handle, char *name ); int jabber_remove_from_roster( struct gaim_connection *gc, char *handle ); @@ -95,7 +96,7 @@ int presence_send_request( struct gaim_connection *gc, char *handle, char *reque char *set_eval_priority( set_t *set, char *value ); char *set_eval_tls( set_t *set, char *value ); struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children ); -void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node ); +void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node, jabber_cache_event func ); struct xt_node *jabber_cache_get( struct gaim_connection *gc, char *id ); void jabber_cache_entry_free( gpointer entry ); void jabber_cache_clean( struct gaim_connection *gc ); diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 11156258..f26b9617 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -81,7 +81,7 @@ struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_ /* Cache a node/packet for later use. Mainly useful for IQ packets if you need them when you receive the response. Use this BEFORE sending the packet so it'll get an id= tag, and do NOT free() the packet after writing it! */ -void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node ) +void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node, jabber_cache_event func ) { struct jabber_data *jd = gc->proto_data; char *id = g_strdup_printf( "BeeX%04x", next_id++ ); @@ -91,17 +91,10 @@ void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node ) g_free( id ); entry->node = node; + entry->func = func; g_hash_table_insert( jd->node_cache, xt_find_attr( node, "id" ), entry ); } -struct xt_node *jabber_cache_get( struct gaim_connection *gc, char *id ) -{ - struct jabber_data *jd = gc->proto_data; - struct jabber_cache_entry *entry = g_hash_table_lookup( jd->node_cache, id ); - - return entry ? entry->node : NULL; -} - void jabber_cache_entry_free( gpointer data ) { struct jabber_cache_entry *entry = data; @@ -112,6 +105,11 @@ void jabber_cache_entry_free( gpointer data ) gboolean jabber_cache_clean_entry( gpointer key, gpointer entry, gpointer nullpointer ); +/* This one should be called from time to time (from keepalive, in this case) + to make sure things don't stay in the node cache forever. By marking nodes + during the first run and deleting marked nodes during a next run, every + node should be available in the cache for at least a minute (assuming the + function is indeed called every minute). */ void jabber_cache_clean( struct gaim_connection *gc ) { struct jabber_data *jd = gc->proto_data; |