Changeset 5ebff60 for protocols/jabber/jabber_util.c
- Timestamp:
- 2015-02-20T22:50:54Z (9 years ago)
- Branches:
- master
- Children:
- 0b9daac, 3d45471, 7733b8c
- Parents:
- af359b4
- git-author:
- Indent <please@…> (19-02-15 05:47:20)
- git-committer:
- dequis <dx@…> (20-02-15 22:50:54)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/jabber/jabber_util.c
raf359b4 r5ebff60 4 4 * Jabber module - Misc. stuff * 5 5 * * 6 * Copyright 2006-2010 Wilmer van der Gaast <wilmer@gaast.net> 6 * Copyright 2006-2010 Wilmer van der Gaast <wilmer@gaast.net> 7 7 * * 8 8 * This program is free software; you can redistribute it and/or modify * … … 28 28 static unsigned int next_id = 1; 29 29 30 char *set_eval_priority( set_t *set, char *value)30 char *set_eval_priority(set_t *set, char *value) 31 31 { 32 32 account_t *acc = set->data; 33 33 int i; 34 35 if( sscanf( value, "%d", &i ) == 1 ) 36 { 34 35 if (sscanf(value, "%d", &i) == 1) { 37 36 /* Priority is a signed 8-bit integer, according to RFC 3921. */ 38 if ( i < -128 || i > 127 )37 if (i < -128 || i > 127) { 39 38 return SET_INVALID; 40 }41 else39 } 40 } else { 42 41 return SET_INVALID; 43 42 } 43 44 44 /* Only run this stuff if the account is online ATM, 45 45 and if the setting seems to be acceptable. */ 46 if( acc->ic ) 47 { 46 if (acc->ic) { 48 47 /* Although set_eval functions usually are very nice and 49 48 convenient, they have one disadvantage: If I would just … … 51 50 send the old setting because the set->value gets changed 52 51 after the (this) eval returns a non-NULL value. 53 52 54 53 So now I can choose between implementing post-set 55 54 functions next to evals, or just do this little hack: */ 56 57 g_free( set->value);58 set->value = g_strdup( value);59 55 56 g_free(set->value); 57 set->value = g_strdup(value); 58 60 59 /* (Yes, sorry, I prefer the hack. :-P) */ 61 62 presence_send_update( acc->ic);63 } 64 60 61 presence_send_update(acc->ic); 62 } 63 65 64 return value; 66 65 } 67 66 68 char *set_eval_tls( set_t *set, char *value)69 { 70 if ( g_strcasecmp( value, "try" ) == 0 )67 char *set_eval_tls(set_t *set, char *value) 68 { 69 if (g_strcasecmp(value, "try") == 0) { 71 70 return value; 72 else 73 return set_eval_bool( set, value ); 74 } 75 76 struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children ) 71 } else { 72 return set_eval_bool(set, value); 73 } 74 } 75 76 struct xt_node *jabber_make_packet(char *name, char *type, char *to, struct xt_node *children) 77 77 { 78 78 struct xt_node *node; 79 80 node = xt_new_node( name, NULL, children ); 81 82 if( type ) 83 xt_add_attr( node, "type", type ); 84 if( to ) 85 xt_add_attr( node, "to", to ); 86 79 80 node = xt_new_node(name, NULL, children); 81 82 if (type) { 83 xt_add_attr(node, "type", type); 84 } 85 if (to) { 86 xt_add_attr(node, "to", to); 87 } 88 87 89 /* IQ packets should always have an ID, so let's generate one. It 88 90 might get overwritten by jabber_cache_add() if this packet has 89 91 to be saved until we receive a response. Cached packets get 90 92 slightly different IDs so we can recognize them. */ 91 if( strcmp( name, "iq" ) == 0 ) 92 { 93 char *id = g_strdup_printf( "%s%05x", JABBER_PACKET_ID, ( next_id++ ) & 0xfffff ); 94 xt_add_attr( node, "id", id ); 95 g_free( id ); 96 } 97 93 if (strcmp(name, "iq") == 0) { 94 char *id = g_strdup_printf("%s%05x", JABBER_PACKET_ID, (next_id++) & 0xfffff); 95 xt_add_attr(node, "id", id); 96 g_free(id); 97 } 98 98 99 return node; 99 100 } 100 101 101 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code)102 struct xt_node *jabber_make_error_packet(struct xt_node *orig, char *err_cond, char *err_type, char *err_code) 102 103 { 103 104 struct xt_node *node, *c; 104 105 char *to; 105 106 106 107 /* Create the "defined-condition" tag. */ 107 c = xt_new_node( err_cond, NULL, NULL);108 xt_add_attr( c, "xmlns", XMLNS_STANZA_ERROR);109 108 c = xt_new_node(err_cond, NULL, NULL); 109 xt_add_attr(c, "xmlns", XMLNS_STANZA_ERROR); 110 110 111 /* Put it in an <error> tag. */ 111 c = xt_new_node( "error", NULL, c);112 xt_add_attr( c, "type", err_type);113 112 c = xt_new_node("error", NULL, c); 113 xt_add_attr(c, "type", err_type); 114 114 115 /* Add the error code, if present */ 115 if (err_code) 116 xt_add_attr( c, "code", err_code ); 117 116 if (err_code) { 117 xt_add_attr(c, "code", err_code); 118 } 119 118 120 /* To make the actual error packet, we copy the original packet and 119 121 add our <error>/type="error" tag. Including the original packet 120 122 is recommended, so let's just do it. */ 121 node = xt_dup( orig);122 xt_add_child( node, c);123 xt_add_attr( node, "type", "error");124 123 node = xt_dup(orig); 124 xt_add_child(node, c); 125 xt_add_attr(node, "type", "error"); 126 125 127 /* Return to sender. */ 126 if( ( to = xt_find_attr( node, "from" ) ) ) 127 { 128 xt_add_attr( node, "to", to ); 129 xt_remove_attr( node, "from" ); 130 } 131 128 if ((to = xt_find_attr(node, "from"))) { 129 xt_add_attr(node, "to", to); 130 xt_remove_attr(node, "from"); 131 } 132 132 133 return node; 133 134 } … … 136 137 them when you receive the response. Use this BEFORE sending the packet so 137 138 it'll get a new id= tag, and do NOT free() the packet after sending it! */ 138 void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func)139 void jabber_cache_add(struct im_connection *ic, struct xt_node *node, jabber_cache_event func) 139 140 { 140 141 struct jabber_data *jd = ic->proto_data; 141 struct jabber_cache_entry *entry = g_new0( struct jabber_cache_entry, 1);142 struct jabber_cache_entry *entry = g_new0(struct jabber_cache_entry, 1); 142 143 md5_state_t id_hash; 143 144 md5_byte_t id_sum[16]; 144 145 char *id, *asc_hash; 145 146 next_id 147 146 147 next_id++; 148 148 149 id_hash = jd->cached_id_prefix; 149 md5_append( &id_hash, (md5_byte_t*) &next_id, sizeof( next_id ));150 md5_digest_keep( &id_hash, id_sum);151 asc_hash = base64_encode( id_sum, 12);152 153 id = g_strdup_printf( "%s%s", JABBER_CACHED_ID, asc_hash);154 xt_add_attr( node, "id", id);155 g_free( id);156 g_free( asc_hash);157 150 md5_append(&id_hash, (md5_byte_t *) &next_id, sizeof(next_id)); 151 md5_digest_keep(&id_hash, id_sum); 152 asc_hash = base64_encode(id_sum, 12); 153 154 id = g_strdup_printf("%s%s", JABBER_CACHED_ID, asc_hash); 155 xt_add_attr(node, "id", id); 156 g_free(id); 157 g_free(asc_hash); 158 158 159 entry->node = node; 159 160 entry->func = func; 160 entry->saved_at = time( NULL);161 g_hash_table_insert( jd->node_cache, xt_find_attr( node, "id" ), entry);162 } 163 164 void jabber_cache_entry_free( gpointer data)161 entry->saved_at = time(NULL); 162 g_hash_table_insert(jd->node_cache, xt_find_attr(node, "id"), entry); 163 } 164 165 void jabber_cache_entry_free(gpointer data) 165 166 { 166 167 struct jabber_cache_entry *entry = data; 167 168 xt_free_node( entry->node);169 g_free( entry);170 } 171 172 gboolean jabber_cache_clean_entry( gpointer key, gpointer entry, gpointer nullpointer);168 169 xt_free_node(entry->node); 170 g_free(entry); 171 } 172 173 gboolean jabber_cache_clean_entry(gpointer key, gpointer entry, gpointer nullpointer); 173 174 174 175 /* This one should be called from time to time (from keepalive, in this case) … … 177 178 node should be available in the cache for at least a minute (assuming the 178 179 function is indeed called every minute). */ 179 void jabber_cache_clean( struct im_connection *ic)180 void jabber_cache_clean(struct im_connection *ic) 180 181 { 181 182 struct jabber_data *jd = ic->proto_data; 182 time_t threshold = time( NULL) - JABBER_CACHE_MAX_AGE;183 184 g_hash_table_foreach_remove( jd->node_cache, jabber_cache_clean_entry, &threshold);185 } 186 187 gboolean jabber_cache_clean_entry( gpointer key, gpointer entry_, gpointer threshold_)183 time_t threshold = time(NULL) - JABBER_CACHE_MAX_AGE; 184 185 g_hash_table_foreach_remove(jd->node_cache, jabber_cache_clean_entry, &threshold); 186 } 187 188 gboolean jabber_cache_clean_entry(gpointer key, gpointer entry_, gpointer threshold_) 188 189 { 189 190 struct jabber_cache_entry *entry = entry_; 190 191 time_t *threshold = threshold_; 191 192 192 193 return entry->saved_at < *threshold; 193 194 } 194 195 195 xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node *node)196 xt_status jabber_cache_handle_packet(struct im_connection *ic, struct xt_node *node) 196 197 { 197 198 struct jabber_data *jd = ic->proto_data; 198 199 struct jabber_cache_entry *entry; 199 200 char *s; 200 201 if( ( s = xt_find_attr( node, "id" ) ) == NULL || 202 strncmp( s, JABBER_CACHED_ID, strlen( JABBER_CACHED_ID ) ) != 0 ) 203 { 201 202 if ((s = xt_find_attr(node, "id")) == NULL || 203 strncmp(s, JABBER_CACHED_ID, strlen(JABBER_CACHED_ID)) != 0) { 204 204 /* Silently ignore it, without an ID (or a non-cache 205 205 ID) we don't know how to handle the packet and we … … 207 207 return XT_HANDLED; 208 208 } 209 210 entry = g_hash_table_lookup( jd->node_cache, s ); 211 212 if( entry == NULL ) 213 { 209 210 entry = g_hash_table_lookup(jd->node_cache, s); 211 212 if (entry == NULL) { 214 213 /* 215 214 There's no longer an easy way to see if we generated this 216 215 one or someone else, and there's a ten-minute timeout anyway, 217 216 so meh. 218 217 219 218 imcb_log( ic, "Warning: Received %s-%s packet with unknown/expired ID %s!", 220 219 node->name, xt_find_attr( node, "type" ) ? : "(no type)", s ); 221 220 */ 222 } 223 else if( entry->func ) 224 { 225 return entry->func( ic, node, entry->node ); 226 } 227 221 } else if (entry->func) { 222 return entry->func(ic, node, entry->node); 223 } 224 228 225 return XT_HANDLED; 229 226 } … … 238 235 }; 239 236 240 const struct jabber_away_state *jabber_away_state_by_code( char *code)237 const struct jabber_away_state *jabber_away_state_by_code(char *code) 241 238 { 242 239 int i; 243 244 if ( code == NULL )240 241 if (code == NULL) { 245 242 return NULL; 246 247 for( i = 0; jabber_away_state_list[i].full_name; i ++ ) 248 if( g_strcasecmp( jabber_away_state_list[i].code, code ) == 0 ) 243 } 244 245 for (i = 0; jabber_away_state_list[i].full_name; i++) { 246 if (g_strcasecmp(jabber_away_state_list[i].code, code) == 0) { 249 247 return jabber_away_state_list + i; 250 248 } 249 } 250 251 251 return NULL; 252 252 } 253 253 254 const struct jabber_away_state *jabber_away_state_by_name( char *name)254 const struct jabber_away_state *jabber_away_state_by_name(char *name) 255 255 { 256 256 int i; 257 258 if ( name == NULL )257 258 if (name == NULL) { 259 259 return NULL; 260 261 for( i = 0; jabber_away_state_list[i].full_name; i ++ ) 262 if( g_strcasecmp( jabber_away_state_list[i].full_name, name ) == 0 ) 260 } 261 262 for (i = 0; jabber_away_state_list[i].full_name; i++) { 263 if (g_strcasecmp(jabber_away_state_list[i].full_name, name) == 0) { 263 264 return jabber_away_state_list + i; 264 265 } 266 } 267 265 268 return NULL; 266 269 } 267 270 268 struct jabber_buddy_ask_data 269 { 271 struct jabber_buddy_ask_data { 270 272 struct im_connection *ic; 271 273 char *handle; … … 273 275 }; 274 276 275 static void jabber_buddy_ask_yes( void *data)277 static void jabber_buddy_ask_yes(void *data) 276 278 { 277 279 struct jabber_buddy_ask_data *bla = data; 278 279 presence_send_request( bla->ic, bla->handle, "subscribed");280 281 imcb_ask_add( bla->ic, bla->handle, NULL);282 283 g_free( bla->handle);284 g_free( bla);285 } 286 287 static void jabber_buddy_ask_no( void *data)280 281 presence_send_request(bla->ic, bla->handle, "subscribed"); 282 283 imcb_ask_add(bla->ic, bla->handle, NULL); 284 285 g_free(bla->handle); 286 g_free(bla); 287 } 288 289 static void jabber_buddy_ask_no(void *data) 288 290 { 289 291 struct jabber_buddy_ask_data *bla = data; 290 291 presence_send_request( bla->ic, bla->handle, "unsubscribed");292 293 g_free( bla->handle);294 g_free( bla);295 } 296 297 void jabber_buddy_ask( struct im_connection *ic, char *handle)298 { 299 struct jabber_buddy_ask_data *bla = g_new0( struct jabber_buddy_ask_data, 1);292 293 presence_send_request(bla->ic, bla->handle, "unsubscribed"); 294 295 g_free(bla->handle); 296 g_free(bla); 297 } 298 299 void jabber_buddy_ask(struct im_connection *ic, char *handle) 300 { 301 struct jabber_buddy_ask_data *bla = g_new0(struct jabber_buddy_ask_data, 1); 300 302 char *buf; 301 303 302 304 bla->ic = ic; 303 bla->handle = g_strdup( handle);304 305 buf = g_strdup_printf( "The user %s wants to add you to his/her buddy list.", handle);306 imcb_ask( ic, buf, bla, jabber_buddy_ask_yes, jabber_buddy_ask_no);307 g_free( buf);305 bla->handle = g_strdup(handle); 306 307 buf = g_strdup_printf("The user %s wants to add you to his/her buddy list.", handle); 308 imcb_ask(ic, buf, bla, jabber_buddy_ask_yes, jabber_buddy_ask_no); 309 g_free(buf); 308 310 } 309 311 310 312 /* Compares just the bare portions of two Jabber IDs. */ 311 int jabber_compare_jid( const char *jid1, const char *jid2)313 int jabber_compare_jid(const char *jid1, const char *jid2) 312 314 { 313 315 int i; 314 315 for( i = 0; ; i ++ ) 316 { 317 if( jid1[i] == '\0' || jid1[i] == '/' || jid2[i] == '\0' || jid2[i] == '/' ) 318 { 319 if( ( jid1[i] == '\0' || jid1[i] == '/' ) && ( jid2[i] == '\0' || jid2[i] == '/' ) ) 316 317 for (i = 0;; i++) { 318 if (jid1[i] == '\0' || jid1[i] == '/' || jid2[i] == '\0' || jid2[i] == '/') { 319 if ((jid1[i] == '\0' || jid1[i] == '/') && (jid2[i] == '\0' || jid2[i] == '/')) { 320 320 break; 321 } 321 322 return FALSE; 322 323 } 323 if( g_ascii_tolower( jid1[i] ) != g_ascii_tolower( jid2[i] ) ) 324 { 324 if (g_ascii_tolower(jid1[i]) != g_ascii_tolower(jid2[i])) { 325 325 return FALSE; 326 326 } 327 327 } 328 328 329 329 return TRUE; 330 330 } … … 332 332 /* The /resource part is case sensitive. This stops once we see a slash. 333 333 Returns a new string. Don't leak it! */ 334 char *jabber_normalize( const char *orig)334 char *jabber_normalize(const char *orig) 335 335 { 336 336 char *lower, *new, *s; 337 337 338 if ( ! ( s = strchr( orig, '/' ) ) ) 339 return g_utf8_strdown( orig, -1 ); 340 341 lower = g_utf8_strdown( orig, (s - orig) ); /* stop in s */ 342 new = g_strconcat( lower, s, NULL ); 343 g_free( lower ); 338 if (!(s = strchr(orig, '/'))) { 339 return g_utf8_strdown(orig, -1); 340 } 341 342 lower = g_utf8_strdown(orig, (s - orig)); /* stop in s */ 343 new = g_strconcat(lower, s, NULL); 344 g_free(lower); 344 345 return new; 345 346 } … … 347 348 /* Similar to jabber_normalize, but works with addresses in the form 348 349 * resource=chatroom@example.com */ 349 char *jabber_normalize_ext( const char *orig)350 char *jabber_normalize_ext(const char *orig) 350 351 { 351 352 char *lower, *new, *s; 352 353 353 if ( ! ( s = strchr( orig, '=' ) ) ) 354 return g_utf8_strdown( orig, -1 ); 355 356 lower = g_utf8_strdown( s, -1 ); /* start in s */ 354 if (!(s = strchr(orig, '='))) { 355 return g_utf8_strdown(orig, -1); 356 } 357 358 lower = g_utf8_strdown(s, -1); /* start in s */ 357 359 358 360 *s = 0; 359 new = g_strconcat( orig, lower, NULL);361 new = g_strconcat(orig, lower, NULL); 360 362 *s = '='; 361 363 362 g_free( lower);364 g_free(lower); 363 365 return new; 364 366 } … … 369 371 to deal with that properly. Set their ->resource property to NULL. Do *NOT* 370 372 allow to mix this stuff, though... */ 371 struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid_)373 struct jabber_buddy *jabber_buddy_add(struct im_connection *ic, char *full_jid_) 372 374 { 373 375 struct jabber_data *jd = ic->proto_data; 374 376 struct jabber_buddy *bud, *new, *bi; 375 377 char *s, *full_jid; 376 377 full_jid = jabber_normalize( full_jid_);378 379 if ( ( s = strchr( full_jid, '/' ) ) )378 379 full_jid = jabber_normalize(full_jid_); 380 381 if ((s = strchr(full_jid, '/'))) { 380 382 *s = 0; 381 382 new = g_new0( struct jabber_buddy, 1 ); 383 384 if( ( bud = g_hash_table_lookup( jd->buddies, full_jid ) ) ) 385 {383 } 384 385 new = g_new0(struct jabber_buddy, 1); 386 387 if ((bud = g_hash_table_lookup(jd->buddies, full_jid))) { 386 388 /* The first entry is always a bare JID. If there are more, we 387 389 should ignore the first one here. */ 388 if ( bud->next )390 if (bud->next) { 389 391 bud = bud->next; 390 392 } 393 391 394 /* If this is a transport buddy or whatever, it can't have more 392 395 than one instance, so this is always wrong: */ 393 if( s == NULL || bud->resource == NULL ) 394 { 395 if( s ) *s = '/'; 396 g_free( new ); 397 g_free( full_jid ); 396 if (s == NULL || bud->resource == NULL) { 397 if (s) { 398 *s = '/'; 399 } 400 g_free(new); 401 g_free(full_jid); 398 402 return NULL; 399 403 } 400 404 401 405 new->bare_jid = bud->bare_jid; 402 406 403 407 /* We already have another resource for this buddy, add the 404 408 new one to the list. */ 405 for( bi = bud; bi; bi = bi->next ) 406 { 409 for (bi = bud; bi; bi = bi->next) { 407 410 /* Check for dupes. */ 408 if( strcmp( bi->resource, s + 1 ) == 0 ) 409 { 411 if (strcmp(bi->resource, s + 1) == 0) { 410 412 *s = '/'; 411 g_free( new);412 g_free( full_jid);413 g_free(new); 414 g_free(full_jid); 413 415 return NULL; 414 416 } 415 417 /* Append the new item to the list. */ 416 else if( bi->next == NULL ) 417 { 418 else if (bi->next == NULL) { 418 419 bi->next = new; 419 420 break; 420 421 } 421 422 } 422 } 423 else 424 { 425 new->full_jid = new->bare_jid = g_strdup( full_jid ); 426 g_hash_table_insert( jd->buddies, new->bare_jid, new ); 427 428 if( s ) 429 { 430 new->next = g_new0( struct jabber_buddy, 1 ); 423 } else { 424 new->full_jid = new->bare_jid = g_strdup(full_jid); 425 g_hash_table_insert(jd->buddies, new->bare_jid, new); 426 427 if (s) { 428 new->next = g_new0(struct jabber_buddy, 1); 431 429 new->next->bare_jid = new->bare_jid; 432 430 new = new->next; 433 431 } 434 432 } 435 436 if( s ) 437 { 433 434 if (s) { 438 435 *s = '/'; 439 436 new->full_jid = full_jid; 440 new->resource = strchr( new->full_jid, '/' ) + 1; 441 } 442 else 443 { 437 new->resource = strchr(new->full_jid, '/') + 1; 438 } else { 444 439 /* Let's waste some more bytes of RAM instead of to make 445 440 memory management a total disaster here. And it saves … … 447 442 new->full_jid = full_jid; 448 443 } 449 444 450 445 return new; 451 446 } … … 454 449 asked for a bare JID, it uses the "resource_select" setting to see which 455 450 resource to pick. */ 456 struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, get_buddy_flags_t flags)451 struct jabber_buddy *jabber_buddy_by_jid(struct im_connection *ic, char *jid_, get_buddy_flags_t flags) 457 452 { 458 453 struct jabber_data *jd = ic->proto_data; 459 454 struct jabber_buddy *bud, *head; 460 455 char *s, *jid; 461 462 jid = jabber_normalize( jid_ ); 463 464 if( ( s = strchr( jid, '/' ) ) ) 465 { 456 457 jid = jabber_normalize(jid_); 458 459 if ((s = strchr(jid, '/'))) { 466 460 int bare_exists = 0; 467 461 468 462 *s = 0; 469 if( ( bud = g_hash_table_lookup( jd->buddies, jid ) ) ) 470 { 463 if ((bud = g_hash_table_lookup(jd->buddies, jid))) { 471 464 bare_exists = 1; 472 473 if ( bud->next )465 466 if (bud->next) { 474 467 bud = bud->next; 475 468 } 469 476 470 /* Just return the first one for this bare JID. */ 477 if( flags & GET_BUDDY_FIRST ) 478 { 471 if (flags & GET_BUDDY_FIRST) { 479 472 *s = '/'; 480 g_free( jid);473 g_free(jid); 481 474 return bud; 482 475 } 483 476 484 477 /* Is this one of those no-resource buddies? */ 485 if( bud->resource == NULL ) 486 { 478 if (bud->resource == NULL) { 487 479 *s = '/'; 488 g_free( jid);480 g_free(jid); 489 481 return NULL; 490 482 } 491 483 492 484 /* See if there's an exact match. */ 493 for ( ; bud; bud = bud->next )494 if ( strcmp( bud->resource, s + 1 ) == 0 )485 for (; bud; bud = bud->next) { 486 if (strcmp(bud->resource, s + 1) == 0) { 495 487 break; 496 } 497 498 if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && 499 ( bare_exists || bee_user_by_handle( ic->bee, ic, jid ) ) ) 500 { 488 } 489 } 490 } 491 492 if (bud == NULL && (flags & GET_BUDDY_CREAT) && 493 (bare_exists || bee_user_by_handle(ic->bee, ic, jid))) { 501 494 *s = '/'; 502 bud = jabber_buddy_add( ic, jid);503 } 504 505 g_free( jid);495 bud = jabber_buddy_add(ic, jid); 496 } 497 498 g_free(jid); 506 499 return bud; 507 } 508 else 509 { 500 } else { 510 501 struct jabber_buddy *best_prio, *best_time; 511 502 char *set; 512 513 head = g_hash_table_lookup( jd->buddies, jid);514 bud = ( head && head->next) ? head->next : head;515 516 g_free( jid);517 518 if ( bud == NULL )503 504 head = g_hash_table_lookup(jd->buddies, jid); 505 bud = (head && head->next) ? head->next : head; 506 507 g_free(jid); 508 509 if (bud == NULL) { 519 510 /* No match. Create it now? */ 520 return ( ( flags & GET_BUDDY_CREAT) &&521 bee_user_by_handle( ic->bee, ic, jid_ )) ?522 jabber_buddy_add( ic, jid_) : NULL;523 else if( bud->resource && ( flags & GET_BUDDY_EXACT ) )511 return ((flags & GET_BUDDY_CREAT) && 512 bee_user_by_handle(ic->bee, ic, jid_)) ? 513 jabber_buddy_add(ic, jid_) : NULL; 514 } else if (bud->resource && (flags & GET_BUDDY_EXACT)) { 524 515 /* We want an exact match, so in thise case there shouldn't be a /resource. */ 525 516 return NULL; 526 else if( bud->resource == NULL || bud->next == NULL )517 } else if (bud->resource == NULL || bud->next == NULL) { 527 518 /* No need for selection if there's only one option. */ 528 519 return bud; 529 else if( flags & GET_BUDDY_FIRST )520 } else if (flags & GET_BUDDY_FIRST) { 530 521 /* Looks like the caller doesn't care about details. */ 531 522 return bud; 532 else if( flags & GET_BUDDY_BARE )523 } else if (flags & GET_BUDDY_BARE) { 533 524 return head; 534 525 } 526 535 527 best_prio = best_time = bud; 536 for( ; bud; bud = bud->next ) 537 { 538 if( bud->priority > best_prio->priority ) 528 for (; bud; bud = bud->next) { 529 if (bud->priority > best_prio->priority) { 539 530 best_prio = bud; 540 if( bud->last_msg > best_time->last_msg ) 531 } 532 if (bud->last_msg > best_time->last_msg) { 541 533 best_time = bud; 542 } 543 544 if( ( set = set_getstr( &ic->acc->set, "resource_select" ) ) == NULL ) 534 } 535 } 536 537 if ((set = set_getstr(&ic->acc->set, "resource_select")) == NULL) { 545 538 return NULL; 546 else if( strcmp( set, "priority" ) == 0 )539 } else if (strcmp(set, "priority") == 0) { 547 540 return best_prio; 548 else if( flags & GET_BUDDY_BARE_OK ) /* && strcmp( set, "activity" ) == 0 */ 549 { 550 if( best_time->last_msg + set_getint( &ic->acc->set, "activity_timeout" ) >= time( NULL ) ) 541 } else if (flags & GET_BUDDY_BARE_OK) { /* && strcmp( set, "activity" ) == 0 */ 542 if (best_time->last_msg + set_getint(&ic->acc->set, "activity_timeout") >= time(NULL)) { 551 543 return best_time; 552 else544 } else { 553 545 return head; 554 }555 else546 } 547 } else { 556 548 return best_time; 549 } 557 550 } 558 551 } … … 565 558 replacing the / with a =. But there should be some stripping (@s are 566 559 allowed in Jabber nicks...). */ 567 struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid_, get_buddy_flags_t flags)560 struct jabber_buddy *jabber_buddy_by_ext_jid(struct im_connection *ic, char *jid_, get_buddy_flags_t flags) 568 561 { 569 562 struct jabber_buddy *bud; 570 563 char *s, *jid; 571 572 jid = jabber_normalize_ext( jid_);573 574 if ( ( s = strchr( jid, '=' ) ) == NULL )564 565 jid = jabber_normalize_ext(jid_); 566 567 if ((s = strchr(jid, '=')) == NULL) { 575 568 return NULL; 576 577 for( bud = jabber_buddy_by_jid( ic, s + 1, GET_BUDDY_FIRST ); bud; bud = bud->next ) 578 {569 } 570 571 for (bud = jabber_buddy_by_jid(ic, s + 1, GET_BUDDY_FIRST); bud; bud = bud->next) { 579 572 /* Hmmm, could happen if not all people in the chat are anonymized? */ 580 if ( bud->ext_jid == NULL )573 if (bud->ext_jid == NULL) { 581 574 continue; 582 583 if( strcmp( bud->ext_jid, jid ) == 0 ) 575 } 576 577 if (strcmp(bud->ext_jid, jid) == 0) { 584 578 break; 585 } 586 587 g_free( jid ); 588 579 } 580 } 581 582 g_free(jid); 583 589 584 return bud; 590 585 } … … 593 588 off-line (because (s)he can still be online from a different location. 594 589 XXX: See above, we should accept bare JIDs too... */ 595 int jabber_buddy_remove( struct im_connection *ic, char *full_jid_)590 int jabber_buddy_remove(struct im_connection *ic, char *full_jid_) 596 591 { 597 592 struct jabber_data *jd = ic->proto_data; 598 593 struct jabber_buddy *bud, *prev = NULL, *bi; 599 594 char *s, *full_jid; 600 601 full_jid = jabber_normalize( full_jid_);602 603 if ( ( s = strchr( full_jid, '/' ) ) )595 596 full_jid = jabber_normalize(full_jid_); 597 598 if ((s = strchr(full_jid, '/'))) { 604 599 *s = 0; 605 606 if( ( bud = g_hash_table_lookup( jd->buddies, full_jid ) ) ) 607 { 608 if( bud->next ) 609 bud = (prev=bud)->next; 610 600 } 601 602 if ((bud = g_hash_table_lookup(jd->buddies, full_jid))) { 603 if (bud->next) { 604 bud = (prev = bud)->next; 605 } 606 611 607 /* If there's only one item in the list (and if the resource 612 608 matches), removing it is simple. (And the hash reference 613 609 should be removed too!) */ 614 if( bud->next == NULL && 615 ( ( s == NULL && bud->resource == NULL ) || 616 ( bud->resource && s && strcmp( bud->resource, s + 1 ) == 0 ) ) ) 617 { 618 int st = jabber_buddy_remove_bare( ic, full_jid ); 619 g_free( full_jid ); 610 if (bud->next == NULL && 611 ((s == NULL && bud->resource == NULL) || 612 (bud->resource && s && strcmp(bud->resource, s + 1) == 0))) { 613 int st = jabber_buddy_remove_bare(ic, full_jid); 614 g_free(full_jid); 620 615 return st; 621 } 622 else if( s == NULL || bud->resource == NULL ) 623 { 616 } else if (s == NULL || bud->resource == NULL) { 624 617 /* Tried to remove a bare JID while this JID does seem 625 618 to have resources... (Or the opposite.) *sigh* */ 626 g_free( full_jid);619 g_free(full_jid); 627 620 return 0; 628 } 629 else 630 { 631 for( bi = bud; bi; bi = (prev=bi)->next ) 632 if( strcmp( bi->resource, s + 1 ) == 0 ) 621 } else { 622 for (bi = bud; bi; bi = (prev = bi)->next) { 623 if (strcmp(bi->resource, s + 1) == 0) { 633 624 break; 634 635 g_free( full_jid ); 636 637 if( bi ) 638 { 639 if( prev ) 625 } 626 } 627 628 g_free(full_jid); 629 630 if (bi) { 631 if (prev) { 640 632 prev->next = bi->next; 641 else633 } else { 642 634 /* Don't think this should ever happen anymore. */ 643 g_hash_table_replace( jd->buddies, bi->bare_jid, bi->next ); 644 645 g_free( bi->ext_jid ); 646 g_free( bi->full_jid ); 647 g_free( bi->away_message ); 648 g_free( bi ); 649 635 g_hash_table_replace(jd->buddies, bi->bare_jid, bi->next); 636 } 637 638 g_free(bi->ext_jid); 639 g_free(bi->full_jid); 640 g_free(bi->away_message); 641 g_free(bi); 642 650 643 return 1; 651 } 652 else 653 { 644 } else { 654 645 return 0; 655 646 } 656 647 } 657 } 658 else 659 { 660 g_free( full_jid ); 648 } else { 649 g_free(full_jid); 661 650 return 0; 662 651 } … … 666 655 specified bare JID. Use this when removing someone from the contact 667 656 list, for example. */ 668 int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid)657 int jabber_buddy_remove_bare(struct im_connection *ic, char *bare_jid) 669 658 { 670 659 struct jabber_data *jd = ic->proto_data; 671 660 struct jabber_buddy *bud, *next; 672 673 if ( strchr( bare_jid, '/' ) )661 662 if (strchr(bare_jid, '/')) { 674 663 return 0; 675 676 if( ( bud = jabber_buddy_by_jid( ic, bare_jid, GET_BUDDY_FIRST ) ) ) 677 {664 } 665 666 if ((bud = jabber_buddy_by_jid(ic, bare_jid, GET_BUDDY_FIRST))) { 678 667 /* Most important: Remove the hash reference. We don't know 679 668 this buddy anymore. */ 680 g_hash_table_remove( jd->buddies, bud->bare_jid);681 g_free( bud->bare_jid);682 669 g_hash_table_remove(jd->buddies, bud->bare_jid); 670 g_free(bud->bare_jid); 671 683 672 /* Deallocate the linked list of resources. */ 684 while( bud ) 685 { 673 while (bud) { 686 674 /* ext_jid && anonymous means that this buddy is 687 675 specific to one groupchat (the one we're 688 676 currently cleaning up) so it can be deleted 689 677 completely. */ 690 if( bud->ext_jid && bud->flags & JBFLAG_IS_ANONYMOUS ) 691 imcb_remove_buddy( ic, bud->ext_jid, NULL ); 692 678 if (bud->ext_jid && bud->flags & JBFLAG_IS_ANONYMOUS) { 679 imcb_remove_buddy(ic, bud->ext_jid, NULL); 680 } 681 693 682 next = bud->next; 694 g_free( bud->ext_jid);695 g_free( bud->full_jid);696 g_free( bud->away_message);697 g_free( bud);683 g_free(bud->ext_jid); 684 g_free(bud->full_jid); 685 g_free(bud->away_message); 686 g_free(bud); 698 687 bud = next; 699 688 } 700 689 701 690 return 1; 702 } 703 else 704 { 691 } else { 705 692 return 0; 706 693 } 707 694 } 708 695 709 static gboolean jabber_buddy_remove_all_cb( gpointer key, gpointer value, gpointer data)696 static gboolean jabber_buddy_remove_all_cb(gpointer key, gpointer value, gpointer data) 710 697 { 711 698 struct jabber_buddy *bud, *next; 712 699 713 700 bud = value; 714 if ( bud->bare_jid != bud->full_jid )715 g_free( bud->bare_jid);716 while( bud )717 {701 if (bud->bare_jid != bud->full_jid) { 702 g_free(bud->bare_jid); 703 } 704 while (bud) { 718 705 next = bud->next; 719 g_free( bud->ext_jid);720 g_free( bud->full_jid);721 g_free( bud->away_message);722 g_free( bud);706 g_free(bud->ext_jid); 707 g_free(bud->full_jid); 708 g_free(bud->away_message); 709 g_free(bud); 723 710 bud = next; 724 711 } 725 712 726 713 return TRUE; 727 714 } 728 715 729 void jabber_buddy_remove_all( struct im_connection *ic)716 void jabber_buddy_remove_all(struct im_connection *ic) 730 717 { 731 718 struct jabber_data *jd = ic->proto_data; 732 733 g_hash_table_foreach_remove( jd->buddies, jabber_buddy_remove_all_cb, NULL);734 g_hash_table_destroy( jd->buddies);735 } 736 737 time_t jabber_get_timestamp( struct xt_node *xt)719 720 g_hash_table_foreach_remove(jd->buddies, jabber_buddy_remove_all_cb, NULL); 721 g_hash_table_destroy(jd->buddies); 722 } 723 724 time_t jabber_get_timestamp(struct xt_node *xt) 738 725 { 739 726 struct xt_node *c; … … 744 731 745 732 /* XEP-0091 has <x> */ 746 c = xt_find_node_by_attr( xt->children, "x", "xmlns", XMLNS_DELAY_OLD);747 748 if ( !c || !( s = xt_find_attr( c, "stamp" ) )) {733 c = xt_find_node_by_attr(xt->children, "x", "xmlns", XMLNS_DELAY_OLD); 734 735 if (!c || !(s = xt_find_attr(c, "stamp"))) { 749 736 is_old = FALSE; 750 737 751 738 /* XEP-0203 has <delay> */ 752 c = xt_find_node_by_attr( xt->children, "delay", "xmlns", XMLNS_DELAY);753 if ( !c || !( s = xt_find_attr( c, "stamp" ) )) {739 c = xt_find_node_by_attr(xt->children, "delay", "xmlns", XMLNS_DELAY); 740 if (!c || !(s = xt_find_attr(c, "stamp"))) { 754 741 return 0; 755 742 } 756 743 } 757 758 memset( &tp, 0, sizeof( tp ));744 745 memset(&tp, 0, sizeof(tp)); 759 746 760 747 /* The other main difference between XEPs is the timestamp format */ 761 748 format = (is_old) ? "%4d%2d%2dT%2d:%2d:%2d" : "%4d-%2d-%2dT%2d:%2d:%2dZ"; 762 749 763 if ( sscanf(s, format, &tp.tm_year, &tp.tm_mon, &tp.tm_mday,764 &tp.tm_hour, &tp.tm_min, &tp.tm_sec ) != 6 )750 if (sscanf(s, format, &tp.tm_year, &tp.tm_mon, &tp.tm_mday, 751 &tp.tm_hour, &tp.tm_min, &tp.tm_sec) != 6) { 765 752 return 0; 766 753 } 754 767 755 tp.tm_year -= 1900; 768 tp.tm_mon 769 770 return mktime_utc( &tp);771 } 772 773 struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns)756 tp.tm_mon--; 757 758 return mktime_utc(&tp); 759 } 760 761 struct jabber_error *jabber_error_parse(struct xt_node *node, char *xmlns) 774 762 { 775 763 struct jabber_error *err; 776 764 struct xt_node *c; 777 765 char *s; 778 779 if ( node == NULL )766 767 if (node == NULL) { 780 768 return NULL; 781 782 err = g_new0( struct jabber_error, 1 ); 783 err ->type = xt_find_attr( node, "type");784 785 for( c = node->children; c; c = c->next ) 786 {787 if ( !( s = xt_find_attr( c, "xmlns" )) ||788 strcmp( s, xmlns ) != 0 )769 } 770 771 err = g_new0(struct jabber_error, 1); 772 err->type = xt_find_attr(node, "type"); 773 774 for (c = node->children; c; c = c->next) { 775 if (!(s = xt_find_attr(c, "xmlns")) || 776 strcmp(s, xmlns) != 0) { 789 777 continue; 790 791 if( strcmp( c->name, "text" ) != 0 ) 792 {778 } 779 780 if (strcmp(c->name, "text") != 0) { 793 781 err->code = c->name; 794 782 } 795 783 /* Only use the text if it doesn't have an xml:lang attribute, 796 784 if it's empty or if it's set to something English. */ 797 else if( !( s = xt_find_attr( c, "xml:lang" ) ) || 798 !*s || strncmp( s, "en", 2 ) == 0 ) 799 { 785 else if (!(s = xt_find_attr(c, "xml:lang")) || 786 !*s || strncmp(s, "en", 2) == 0) { 800 787 err->text = c->text; 801 788 } 802 789 } 803 790 804 791 return err; 805 792 } 806 793 807 void jabber_error_free( struct jabber_error *err)808 { 809 g_free( err);810 } 811 812 gboolean jabber_set_me( struct im_connection *ic, const char *me)794 void jabber_error_free(struct jabber_error *err) 795 { 796 g_free(err); 797 } 798 799 gboolean jabber_set_me(struct im_connection *ic, const char *me) 813 800 { 814 801 struct jabber_data *jd = ic->proto_data; 815 816 if ( strchr( me, '@' ) == NULL )802 803 if (strchr(me, '@') == NULL) { 817 804 return FALSE; 818 819 g_free( jd->username ); 820 g_free( jd->me ); 821 822 jd->me = jabber_normalize( me ); 823 jd->server = strchr( jd->me, '@' ); 824 jd->username = g_strndup( jd->me, jd->server - jd->me ); 825 jd->server ++; 805 } 806 807 g_free(jd->username); 808 g_free(jd->me); 809 810 jd->me = jabber_normalize(me); 811 jd->server = strchr(jd->me, '@'); 812 jd->username = g_strndup(jd->me, jd->server - jd->me); 813 jd->server++; 826 814 827 815 /* Set the "internal" account username, for groupchats */ 828 g_free( jd->internal_jid);829 jd->internal_jid = g_strdup( jd->me);830 816 g_free(jd->internal_jid); 817 jd->internal_jid = g_strdup(jd->me); 818 831 819 return TRUE; 832 820 }
Note: See TracChangeset
for help on using the changeset viewer.