diff options
-rw-r--r-- | protocols/jabber/io.c | 33 | ||||
-rw-r--r-- | protocols/jabber/iq.c | 34 | ||||
-rw-r--r-- | protocols/jabber/jabber.c | 6 | ||||
-rw-r--r-- | protocols/jabber/jabber.h | 6 | ||||
-rw-r--r-- | protocols/jabber/jabber_util.c | 29 | ||||
-rw-r--r-- | protocols/jabber/sasl.c | 10 |
6 files changed, 105 insertions, 13 deletions
diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c index 8f2ce0f1..333e3123 100644 --- a/protocols/jabber/io.c +++ b/protocols/jabber/io.c @@ -218,7 +218,7 @@ static xt_status jabber_pkt_features( struct xt_node *node, gpointer data ) { struct gaim_connection *gc = data; struct jabber_data *jd = gc->proto_data; - struct xt_node *c; + struct xt_node *c, *reply; c = xt_find_node( node->children, "starttls" ); if( c ) @@ -230,9 +230,36 @@ static xt_status jabber_pkt_features( struct xt_node *node, gpointer data ) */ } + if( ( c = xt_find_node( node->children, "bind" ) ) ) + { + 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_packet( gc, reply ); + + if( !jabber_write_packet( gc, reply ) ) + return XT_ABORT; + + jd->flags |= JFLAG_WAIT_BIND; + } + + if( ( c = xt_find_node( node->children, "session" ) ) ) + { + 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_packet( gc, reply ); + + if( !jabber_write_packet( gc, reply ) ) + return XT_ABORT; + + jd->flags |= JFLAG_WAIT_SESSION; + } + /* This flag is already set if we authenticated via SASL, so now - we can resume the session in the new stream. */ - if( jd->flags & JFLAG_AUTHENTICATED ) + we can resume the session in the new stream, if we don't have + to bind/initialize the session. */ + if( jd->flags & JFLAG_AUTHENTICATED && ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 ) { if( !jabber_get_roster( gc ) ) return XT_ABORT; diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index bcce5289..fbb4a38b 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -27,7 +27,7 @@ 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; + struct xt_node *query, *reply = NULL, *orig = NULL; char *s, *type, *xmlns; int st; @@ -39,6 +39,9 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) xmlns = xt_find_attr( query, "xmlns" ); + if( ( s = xt_find_attr( node, "id" ) ) ) + orig = jabber_packet_from_cache( gc, s ); + if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:auth" ) == 0 ) { /* Time to authenticate ourselves! */ @@ -81,8 +84,8 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) } reply = jabber_make_packet( "iq", "set", NULL, reply ); + jabber_cache_packet( gc, reply ); st = jabber_write_packet( gc, reply ); - xt_free_node( reply ); return st ? XT_HANDLED : XT_ABORT; } @@ -105,16 +108,35 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) presence_announce( gc ); } - else if( strcmp( type, "result" ) == 0 ) + else if( strcmp( type, "result" ) == 0 && orig ) { - /* If we weren't authenticated yet, let's assume we are now. - There are cleaner ways to do this, probably, but well.. */ - if( !( jd->flags & JFLAG_AUTHENTICATED ) ) + struct xt_node *node; + + if( !( jd->flags & JFLAG_AUTHENTICATED ) && + ( node = xt_find_node( orig->children, "query" ) ) && + ( node = xt_find_node( node->children, "username" ) ) && + node->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; } + else if( ( node = xt_find_node( orig->children, "bind" ) ) || + ( node = xt_find_node( orig->children, "session" ) ) ) + { + if( strcmp( node->name, "bind" ) == 0 ) + jd->flags &= ~JFLAG_WAIT_BIND; + else if( strcmp( node->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; + } + } } else if( strcmp( type, "error" ) == 0 ) { diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 13eac23e..c8525db5 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -75,6 +75,8 @@ static void jabber_login( account_t *acc ) *jd->server = 0; jd->server ++; + jd->node_cache = xt_new_node( "cache", NULL, NULL ); + if( set_getbool( &acc->set, "ssl" ) ) { signoff( gc ); @@ -102,6 +104,10 @@ static void jabber_close( struct gaim_connection *gc ) if( jd->fd >= 0 ) closesocket( jd->fd ); + if( jd->tx_len ) + g_free( jd->txq ); + + xt_free_node( jd->node_cache ); xt_free( jd->xt ); g_free( jd->username ); diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index f8b604b0..c2d3867e 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -34,6 +34,8 @@ typedef enum JFLAG_STREAM_STARTED = 1, /* Set when we detected the beginning of the stream and want to do auth. */ JFLAG_AUTHENTICATED = 2, /* Set when we're successfully authenticatd. */ JFLAG_STREAM_RESTART = 4, /* Set when we want to restart the stream (after SASL or TLS). */ + JFLAG_WAIT_SESSION = 8, /* Set if we sent a <session> tag and need a reply before we continue. */ + JFLAG_WAIT_BIND = 16, /* ... for <bind> tag. */ } jabber_flags_t; /* iq.c */ @@ -52,6 +54,8 @@ int presence_send( struct gaim_connection *gc, char *to, char *show, char *statu char *set_eval_resprio( 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_packet( struct gaim_connection *gc, struct xt_node *node ); +struct xt_node *jabber_packet_from_cache( struct gaim_connection *gc, char *id ); /* io.c */ int jabber_write_packet( struct gaim_connection *gc, struct xt_node *node ); @@ -81,6 +85,8 @@ struct jabber_data char *username; /* USERNAME@server */ char *server; /* username@SERVER -=> server/domain, not hostname */ + + struct xt_node *node_cache; }; #endif diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 46811d05..88b9e55d 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -51,18 +51,43 @@ 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 ) { - char *id = g_strdup_printf( "BeeX%04x", next_id++ ); struct xt_node *node; node = xt_new_node( name, NULL, children ); - xt_add_attr( node, "id", id ); if( type ) xt_add_attr( node, "type", type ); if( to ) xt_add_attr( node, "to", to ); + return node; +} + +/* 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_packet( struct gaim_connection *gc, struct xt_node *node ) +{ + struct jabber_data *jd = gc->proto_data; + char *id = g_strdup_printf( "BeeX%04x", next_id++ ); + + /* FIXME: Maybe start using g_error() here if nodes still have a parent, for example? */ + + xt_add_attr( node, "id", id ); + xt_add_child( jd->node_cache, node ); g_free( id ); +} + +/* Emptying this cache is a BIG TODO! */ +struct xt_node *jabber_packet_from_cache( struct gaim_connection *gc, char *id ) +{ + struct jabber_data *jd = gc->proto_data; + struct xt_node *node; + char *s; + + for( node = jd->node_cache->children; node; node = node->next ) + if( ( s = xt_find_attr( node, "id" ) ) && strcmp( id, s ) == 0 ) + break; return node; } diff --git a/protocols/jabber/sasl.c b/protocols/jabber/sasl.c index 2f75e733..13ff9d26 100644 --- a/protocols/jabber/sasl.c +++ b/protocols/jabber/sasl.c @@ -70,7 +70,13 @@ xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data ) reply = xt_new_node( "auth", NULL, NULL ); xt_add_attr( reply, "xmlns", SASL_NS ); - if( sup_plain ) + if( sup_digest && 0 ) + { + xt_add_attr( reply, "mechanism", "DIGEST-MD5" ); + + /* The rest will be done later, when we receive a <challenge/>. */ + } + else if( sup_plain ) { int len; @@ -140,5 +146,5 @@ gboolean sasl_supported( struct gaim_connection *gc ) { struct jabber_data *jd = gc->proto_data; - return ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) != NULL; + return ( (void*) ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) ) != NULL; } |