diff options
author | Wilmer van der Gaast <wilmer@gaast.net> | 2006-11-13 00:06:08 +0100 |
---|---|---|
committer | Wilmer van der Gaast <wilmer@gaast.net> | 2006-11-13 00:06:08 +0100 |
commit | 0d3f30f5449cf1730c006314f3dd60843e911ad1 (patch) | |
tree | a9d952e5342e65ee2097295871f3e34e53d93c6c /protocols | |
parent | 47d3ac46306965e9db66096eef8c60c8e7985950 (diff) |
Improved handling of JIDs: Bare JIDs are allowed (*sigh*) and case
insensitivity. Probably not complete yet...
Diffstat (limited to 'protocols')
-rw-r--r-- | protocols/jabber/jabber.c | 20 | ||||
-rw-r--r-- | protocols/jabber/jabber.h | 16 | ||||
-rw-r--r-- | protocols/jabber/jabber_util.c | 168 | ||||
-rw-r--r-- | protocols/jabber/message.c | 10 | ||||
-rw-r--r-- | protocols/jabber/presence.c | 63 |
5 files changed, 174 insertions, 103 deletions
diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 2ef76444..a60cd4aa 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -216,12 +216,12 @@ static int jabber_send_im( struct gaim_connection *gc, char *who, char *message, struct xt_node *node; int st; - bud = jabber_buddy_by_jid( gc, who ); + bud = jabber_buddy_by_jid( gc, who, 0 ); node = xt_new_node( "body", message, NULL ); node = jabber_make_packet( "message", "chat", bud ? bud->full_jid : who, node ); - if( ( jd->flags & JFLAG_WANT_TYPING ) && bud && + if( bud && ( jd->flags & JFLAG_WANT_TYPING ) && ( ( bud->flags & JBFLAG_DOES_XEP85 ) || !( bud->flags & JBFLAG_PROBED_XEP85 ) ) ) { @@ -265,20 +265,24 @@ static void jabber_get_info( struct gaim_connection *gc, char *who ) struct jabber_buddy *bud; if( strchr( who, '/' ) ) - bud = jabber_buddy_by_jid( gc, who ); + bud = jabber_buddy_by_jid( gc, who, 0 ); else - bud = g_hash_table_lookup( jd->buddies, who ); + { + char *s = jabber_normalize( who ); + bud = g_hash_table_lookup( jd->buddies, s ); + g_free( s ); + } while( bud ) { - serv_got_crap( gc, "Buddy %s/%s (%d) information:\nAway state: %s\nAway message: %s", - bud->handle, bud->resource, bud->priority, + serv_got_crap( gc, "Buddy %s (%d) information:\nAway state: %s\nAway message: %s", + bud->full_jid, bud->priority, bud->away_state ? bud->away_state->full_name : "(none)", bud->away_message ? : "(none)" ); bud = bud->next; } - jabber_get_vcard( gc, bud ? bud->handle : who ); + jabber_get_vcard( gc, bud ? bud->full_jid : who ); } static void jabber_set_away( struct gaim_connection *gc, char *state_txt, char *message ) @@ -328,7 +332,7 @@ static int jabber_send_typing( struct gaim_connection *gc, char *who, int typing /* Enable typing notification related code from now. */ jd->flags |= JFLAG_WANT_TYPING; - if( ( bud = jabber_buddy_by_jid( gc, who ) ) == NULL ) + if( ( bud = jabber_buddy_by_jid( gc, who, 0 ) ) == NULL ) { /* Sending typing notifications to unknown buddies is unsupported for now. Shouldn't be a problem, I think. */ diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index da9bfd52..628cb03a 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -49,7 +49,7 @@ typedef enum sure it gets sent only once. */ JBFLAG_DOES_XEP85 = 2, /* Set this when the resource seems to support XEP85 (typing notification shite). */ -} jabber_buddy_flag_t; +} jabber_buddy_flags_t; struct jabber_data { @@ -92,7 +92,7 @@ struct jabber_cache_entry struct jabber_buddy { - char *handle; + char *bare_jid; char *full_jid; char *resource; @@ -101,7 +101,7 @@ struct jabber_buddy char *away_message; time_t last_act; - jabber_buddy_flag_t flags; + jabber_buddy_flags_t flags; struct jabber_buddy *next; }; @@ -159,8 +159,16 @@ 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 ); +char *jabber_normalize( char *orig ); + +typedef enum +{ + GET_BUDDY_CREAT = 1, /* Try to create it, if necessary. */ + GET_BUDDY_EXACT = 2, /* Get an exact message (only makes sense with bare JIDs). */ +} get_buddy_flags_t; + 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 ); +struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid, get_buddy_flags_t flags ); int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid ); int jabber_buddy_remove_bare( struct gaim_connection *gc, char *bare_jid ); diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 07d7a2fd..7b1961e0 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -250,33 +250,63 @@ void jabber_buddy_ask( struct gaim_connection *gc, char *handle ) g_free( buf ); } +/* Returns a new string. Don't leak it! */ +char *jabber_normalize( char *orig ) +{ + int len, i; + char *new; + + len = strlen( orig ); + new = g_new( char, len + 1 ); + for( i = 0; i < len; i ++ ) + new[i] = tolower( orig[i] ); + + new[i] = 0; + return new; +} + /* 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 ) + FULL jid or if we already have this buddy/resource. XXX: No, great, actually + buddies from transports don't (usually) have resources. So we'll really have + to deal with that properly. Set their ->resource property to NULL. Do *NOT* + allow to mix this stuff, though... */ +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; + char *s, *full_jid; - if( !( s = strchr( full_jid, '/' ) ) ) - return NULL; + full_jid = jabber_normalize( full_jid_ ); + + if( ( s = strchr( full_jid, '/' ) ) ) + *s = 0; new = g_new0( struct jabber_buddy, 1 ); - *s = 0; if( ( bud = g_hash_table_lookup( jd->buddies, full_jid ) ) ) { - new->handle = bud->handle; + /* If this is a transport buddy or whatever, it can't have more + than one instance, so this is always wrong: */ + if( s == NULL || bud->resource == NULL ) + { + if( s ) *s = '/'; + g_free( new ); + g_free( full_jid ); + return NULL; + } + + new->bare_jid = bud->bare_jid; /* 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 ) + /* Check for dupes. */ + if( g_strcasecmp( bi->resource, s + 1 ) == 0 ) { *s = '/'; g_free( new ); + g_free( full_jid ); return NULL; } /* Append the new item to the list. */ @@ -289,13 +319,22 @@ struct jabber_buddy *jabber_buddy_add( struct gaim_connection *gc, char *full_ji } else { - new->handle = g_strdup( full_jid ); - g_hash_table_insert( jd->buddies, new->handle, new ); + new->bare_jid = g_strdup( full_jid ); + g_hash_table_insert( jd->buddies, new->bare_jid, new ); } - *s = '/'; - new->full_jid = g_strdup( full_jid ); - new->resource = strchr( new->full_jid, '/' ) + 1; + if( s ) + { + *s = '/'; + new->full_jid = full_jid; + new->resource = strchr( new->full_jid, '/' ) + 1; + } + else + { + /* Let's waste some more bytes of RAM instead of to make + memory management a total disaster here.. */ + new->full_jid = full_jid; + } return new; } @@ -303,26 +342,56 @@ struct jabber_buddy *jabber_buddy_add( struct gaim_connection *gc, char *full_ji /* Finds a buddy from our structures. Can find both full- and bare JIDs. When asked for a bare JID, it uses the "resource_select" setting to see which resource to pick. */ -struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid ) +struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid_, get_buddy_flags_t flags ) { struct jabber_data *jd = gc->proto_data; struct jabber_buddy *bud; - char *s; + char *s, *jid; + + jid = jabber_normalize( jid_ ); 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; + { + /* Is this one of those no-resource buddies? */ + if( bud->resource == NULL ) + { + bud = NULL; + } + else + { + /* See if there's an exact match. */ + for( ; bud; bud = bud->next ) + if( g_strcasecmp( bud->resource, s + 1 ) == 0 ) + break; + } + } + + *s = '/'; + if( bud == NULL && ( flags & GET_BUDDY_CREAT ) ) + bud = jabber_buddy_add( gc, jid ); + + g_free( jid ); + return bud; } else { struct jabber_buddy *best_prio, *best_time; char *set; - best_prio = best_time = bud = g_hash_table_lookup( jd->buddies, jid ); + bud = g_hash_table_lookup( jd->buddies, jid ); + + g_free( jid ); + + /* An exact match, or only one option. */ + if( bud == NULL ) + return ( flags & GET_BUDDY_CREAT ) ? jabber_buddy_add( gc, jid ) : NULL; + else if( ( bud->resource == NULL || bud->next == NULL ) ) + return bud; + + best_prio = best_time = bud; for( ; bud; bud = bud->next ) { if( bud->priority > best_prio->priority ) @@ -338,42 +407,54 @@ struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid else /* if( strcmp( set, "priority" ) == 0 ) */ return best_prio; } - - *s = '/'; - return bud; } /* Remove one specific full JID from our list. Use this when a buddy goes - off-line (because (s)he can still be online from a different location. */ -int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid ) + off-line (because (s)he can still be online from a different location. + XXX: See above, we should accept bare JIDs too... */ +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; + char *s, *full_jid; - if( !( s = strchr( full_jid, '/' ) ) ) - return 0; + full_jid = jabber_normalize( full_jid_ ); + + if( ( s = strchr( full_jid, '/' ) ) ) + *s = 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 ) + if( bud->next == NULL && ( ( s == NULL || bud->resource == NULL ) || g_strcasecmp( bud->resource, s + 1 ) == 0 ) ) { - g_hash_table_remove( jd->buddies, bud->handle ); - g_free( bud->handle ); + g_hash_table_remove( jd->buddies, bud->bare_jid ); + g_free( bud->bare_jid ); g_free( bud->full_jid ); g_free( bud->away_message ); g_free( bud ); + + g_free( full_jid ); + + return 1; + } + else if( s == NULL || bud->resource == NULL ) + { + /* Tried to remove a bare JID while this JID does seem + to have resources... (Or the opposite.) *sigh* */ + g_free( full_jid ); + return 0; } else { for( bi = bud, prev = NULL; bi; bi = (prev=bi)->next ) - if( strcmp( bi->resource, s + 1 ) == 0 ) + if( g_strcasecmp( bi->resource, s + 1 ) == 0 ) break; + g_free( full_jid ); + if( bi ) { if( prev ) @@ -381,25 +462,23 @@ int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid ) 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_hash_table_replace( jd->buddies, bi->bare_jid, bi->next ); g_free( bi->full_jid ); g_free( bi->away_message ); g_free( bi ); + + return 1; } else { - *s = '/'; return 0; } } - - *s = '/'; - return 1; } else { - *s = '/'; + g_free( full_jid ); return 0; } } @@ -407,19 +486,22 @@ int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid ) /* Remove a buddy completely; removes all resources that belong to the specified bare JID. Use this when removing someone from the contact list, for example. */ -int jabber_buddy_remove_bare( struct gaim_connection *gc, char *bare_jid ) +int jabber_buddy_remove_bare( struct gaim_connection *gc, char *bare_jid_ ) { struct jabber_data *jd = gc->proto_data; struct jabber_buddy *bud, *next; + char *bare_jid; - if( strchr( bare_jid, '/' ) ) + if( strchr( bare_jid_, '/' ) ) return 0; + bare_jid = jabber_normalize( bare_jid_ ); + if( ( bud = g_hash_table_lookup( jd->buddies, bare_jid ) ) ) { /* Most important: Remove the hash reference. We don't know this buddy anymore. */ - g_hash_table_remove( jd->buddies, bud->handle ); + g_hash_table_remove( jd->buddies, bud->bare_jid ); /* Deallocate the linked list of resources. */ while( bud ) @@ -431,10 +513,12 @@ int jabber_buddy_remove_bare( struct gaim_connection *gc, char *bare_jid ) bud = next; } + g_free( bare_jid ); return 1; } else { + g_free( bare_jid ); return 0; } } diff --git a/protocols/jabber/message.c b/protocols/jabber/message.c index ad19a1dc..ac72f661 100644 --- a/protocols/jabber/message.c +++ b/protocols/jabber/message.c @@ -46,7 +46,7 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) if( ( s = strchr( from, '/' ) ) ) { - if( ( bud = jabber_buddy_by_jid( gc, from ) ) ) + if( ( bud = jabber_buddy_by_jid( gc, from, GET_BUDDY_EXACT ) ) ) bud->last_act = time( NULL ); else *s = 0; /* We need to generate a bare JID now. */ @@ -75,7 +75,7 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) fullmsg = g_string_append( fullmsg, body->text ); if( fullmsg->len > 0 ) - serv_got_im( gc, bud ? bud->handle : from, fullmsg->str, 0, 0, fullmsg->len ); + serv_got_im( gc, bud ? bud->bare_jid : from, fullmsg->str, 0, 0, fullmsg->len ); g_string_free( fullmsg, TRUE ); @@ -83,18 +83,18 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) if( xt_find_node( node->children, "composing" ) ) { bud->flags |= JBFLAG_DOES_XEP85; - serv_got_typing( gc, bud ? bud->handle : from, 0, 1 ); + serv_got_typing( gc, bud ? bud->bare_jid : from, 0, 1 ); } /* No need to send a "stopped typing" signal when there's a message. */ else if( xt_find_node( node->children, "active" ) && ( body == NULL ) ) { bud->flags |= JBFLAG_DOES_XEP85; - serv_got_typing( gc, bud ? bud->handle : from, 0, 0 ); + serv_got_typing( gc, bud ? bud->bare_jid : from, 0, 0 ); } else if( xt_find_node( node->children, "paused" ) ) { bud->flags |= JBFLAG_DOES_XEP85; - serv_got_typing( gc, bud ? bud->handle : from, 0, 2 ); + serv_got_typing( gc, bud ? bud->bare_jid : from, 0, 2 ); } if( s ) diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c index ccd22f60..b56acb51 100644 --- a/protocols/jabber/presence.c +++ b/protocols/jabber/presence.c @@ -37,36 +37,12 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) if( type == NULL ) { - if( ( s = strchr( from, '/' ) ) == NULL ) + if( !( bud = jabber_buddy_by_jid( gc, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) ) { - char *s = xt_to_string( node ); - serv_got_crap( gc, "WARNING: Ignoring presence tag with bare JID: %s", s ); - g_free( s ); + serv_got_crap( gc, "WARNING: Could not handle presence information from JID: %s", from ); return XT_HANDLED; } - if( !( bud = jabber_buddy_by_jid( gc, from ) ) ) - { - /* FOR NOW, s still contains the location of the /. - Keep this in mind when changing things here. :-) */ - - /* We check if the buddy is in the contact list, - because Jabber servers seem to like to send - presence information of buddies we removed - from our list sometimes, for example... */ - - *s = 0; - if( find_buddy( gc, from ) == NULL ) - { - *s = '/'; - serv_got_crap( gc, "WARNING: Ignoring presence information from unknown JID: %s", from ); - return XT_HANDLED; - } - *s = '/'; - - 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 ); @@ -88,36 +64,34 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) else bud->priority = 0; - serv_got_update( gc, bud->handle, 1, 0, 0, 0, + serv_got_update( gc, bud->bare_jid, 1, 0, 0, 0, bud->away_state ? UC_UNAVAILABLE : 0, 0 ); } else if( strcmp( type, "unavailable" ) == 0 ) { - char *s; - - if( ( s = strchr( from, '/' ) ) == NULL ) - { - char *s = xt_to_string( node ); - serv_got_crap( gc, "WARNING: Ignoring presence tag with bare JID: %s\n", s ); - g_free( s ); - return XT_HANDLED; - } - - if( jabber_buddy_by_jid( gc, from ) == NULL ) + if( jabber_buddy_by_jid( gc, from, GET_BUDDY_EXACT ) == NULL ) { serv_got_crap( gc, "WARNING: Received presence information from unknown JID: %s", from ); return XT_HANDLED; } jabber_buddy_remove( gc, 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 ); + if( ( s = strchr( from, '/' ) ) ) + { + *s = 0; - *s = '/'; + /* Only count this as offline if there's no other resource + available anymore. */ + if( jabber_buddy_by_jid( gc, from, 0 ) == NULL ) + serv_got_update( gc, from, 0, 0, 0, 0, 0, 0 ); + + *s = '/'; + } + else + { + serv_got_update( gc, from, 0, 0, 0, 0, 0, 0 ); + } } else if( strcmp( type, "subscribe" ) == 0 ) { @@ -125,6 +99,7 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) } else if( strcmp( type, "subscribed" ) == 0 ) { + /* Not sure about this one, actually... */ serv_got_crap( gc, "%s just accepted your authorization request", from ); } else if( strcmp( type, "unsubscribe" ) == 0 || strcmp( type, "unsubscribed" ) == 0 ) |