comparison mcabber/libjabber/jid.c @ 417:c3ae9251c197

Sync libjabber with upstream Sync with jabberd-1.4.4.
author Mikael Berthe <mikael@lilotux.net>
date Thu, 01 Sep 2005 23:29:21 +0200
parents bf3d6e241714
children
comparison
equal deleted inserted replaced
416:48e7808c4191 417:c3ae9251c197
15 * 15 *
16 * Jabber 16 * Jabber
17 * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/ 17 * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
18 */ 18 */
19 19
20 /**
21 * @file jid.c
22 * @brief representation and normalization of JabberIDs
23 */
24
20 #include "jabber.h" 25 #include "jabber.h"
21 26
22 jid jid_safe(jid id) 27 #ifdef LIBIDN
23 { 28
29 # include <stringprep.h>
30
31
32 /**
33 * @brief datastructure to build the stringprep caches
34 */
35 typedef struct _jid_prep_entry_st {
36 char *preped; /**< the result of the preparation, NULL if unchanged */
37 time_t last_used; /**< when this result has last been successfully used */
38 unsigned int used_count; /**< how often this result has been successfully used */
39 int size; /**< the min buffer size needed to hold the result (strlen+1) */
40 } *_jid_prep_entry_t;
41
42 /**
43 * @brief string preparation cache
44 */
45 typedef struct _jid_prep_cache_st {
46 xht hashtable; /**< the hash table containing the preped strings */
47 pth_mutex_t mutex; /**< mutex controling the access to the hashtable */
48 const Stringprep_profile *profile;
49 /**< the stringprep profile used for this cache */
50 } *_jid_prep_cache_t;
51
52 /**
53 * stringprep cache containging already preped nodes
54 *
55 * we are using global caches here for two reasons:
56 * - I do not see why different instances would want
57 * to have different caches as we are always doing
58 * the same
59 * - For per instance caches I would have to modify the
60 * interface of the jid_*() functions which would break
61 * compatibility with transports
62 */
63 _jid_prep_cache_t _jid_prep_cache_node = NULL;
64
65 /**
66 * stringprep cache containing already preped domains
67 */
68 _jid_prep_cache_t _jid_prep_cache_domain = NULL;
69
70 /**
71 * stringprep cache containing already preped resources
72 */
73 _jid_prep_cache_t _jid_prep_cache_resource = NULL;
74
75 /**
76 * walker for cleaning up stringprep caches
77 *
78 * @param h the hash we are walking through
79 * @param key the key of this item
80 * @param val the value of this item
81 * @param arg delete entries older as this unix timestamp
82 */
83 void _jid_clean_walker(xht h, const char *key, void *val, void *arg) {
84 time_t *keep_newer_as = (time_t*)arg;
85 _jid_prep_entry_t entry = (_jid_prep_entry_t)val;
86
87 if (entry == NULL)
88 return;
89
90 if (entry->last_used <= *keep_newer_as) {
91 xhash_zap(h, key);
92 if (entry->preped != NULL)
93 free(entry->preped);
94 free(entry);
95
96 /* sorry, I have to cast the const away */
97 /* any idea how I could delete the key else? */
98 if (key != NULL)
99 free((void*)key);
100 }
101 }
102
103 /**
104 * walk through a single stringprep cache and check which entries have expired
105 */
106 void _jid_clean_single_cache(_jid_prep_cache_t cache, time_t keep_newer_as) {
107 /* acquire the lock on the cache */
108 pth_mutex_acquire(&(cache->mutex), FALSE, NULL);
109
110 /* walk over all entries */
111 xhash_walk(cache->hashtable, _jid_clean_walker, (void*)&keep_newer_as);
112
113 /* we're done, release the lock on the cache */
114 pth_mutex_release(&(cache->mutex));
115 }
116
117 /**
118 * walk through the stringprep caches and check which entries have expired
119 */
120 void jid_clean_cache() {
121 /* XXX make this configurable? */
122 time_t keep_newer_as = time(NULL) - 900;
123
124 /* cleanup the nodeprep cache */
125 _jid_clean_single_cache(_jid_prep_cache_node, keep_newer_as);
126
127 /* cleanup the domain preparation cache */
128 _jid_clean_single_cache(_jid_prep_cache_domain, keep_newer_as);
129
130 /* cleanup the resourceprep cache */
131 _jid_clean_single_cache(_jid_prep_cache_resource, keep_newer_as);
132 }
133
134 /**
135 * caching wrapper around a stringprep function
136 *
137 * @param in_out_buffer buffer containing what has to be stringpreped and that gets the result
138 * @param max_len size of the buffer
139 * @param cache the used cache, defining also the used stringprep profile
140 * @return the return code of the stringprep call
141 */
142 int _jid_cached_stringprep(char *in_out_buffer, int max_len, _jid_prep_cache_t cache) {
143 _jid_prep_entry_t preped;
144 int result = STRINGPREP_OK;
145
146 /* check that the cache already exists
147 * we can not do anything as we don't know which profile has to be used */
148 if (cache == NULL) {
149 return STRINGPREP_UNKNOWN_PROFILE;
150 }
151
152 /* is there something that has to be stringpreped? */
153 if (in_out_buffer == NULL) {
154 return STRINGPREP_OK;
155 }
156
157 /* acquire the lock on the cache */
158 pth_mutex_acquire(&(cache->mutex), FALSE, NULL);
159
160 /* check if the requested preparation has already been done */
161 preped = (_jid_prep_entry_t)xhash_get(cache->hashtable, in_out_buffer);
162 if (preped != NULL) {
163 /* we already prepared this argument */
164 if (preped->size <= max_len) {
165 /* we can use the result */
166
167 /* update the statistic */
168 preped->used_count++;
169 preped->last_used = time(NULL);
170
171 /* do we need to copy the result? */
172 if (preped->preped != NULL) {
173 /* copy the result */
174 strcpy(in_out_buffer, preped->preped);
175 }
176
177 result = STRINGPREP_OK;
178 } else {
179 /* we need a bigger buffer */
180 result = STRINGPREP_TOO_SMALL_BUFFER;
181 }
182
183 /* we're done, release the lock on the cache */
184 pth_mutex_release(&(cache->mutex));
185 } else {
186 char *original;
187
188 /* stringprep needs time, release the lock on the cache for the meantime */
189 pth_mutex_release(&(cache->mutex));
190
191 /* we have to keep the key */
192 original = strdup(in_out_buffer);
193
194 /* try to prepare the string */
195 result = stringprep(in_out_buffer, max_len, STRINGPREP_NO_UNASSIGNED, cache->profile);
196
197 /* did we manage to prepare the string? */
198 if (result == STRINGPREP_OK && original != NULL) {
199 /* generate an entry for the cache */
200 preped = (_jid_prep_entry_t)malloc(sizeof(struct _jid_prep_entry_st));
201 if (preped != NULL) {
202 /* has there been modified something? */
203 if (j_strcmp(in_out_buffer, original) == 0) {
204 /* no, we don't need to store a copy of the original string */
205 preped->preped = NULL;
206 } else {
207 /* yes, store the stringpreped string */
208 preped->preped = strdup(in_out_buffer);
209 }
210 preped->last_used = time(NULL);
211 preped->used_count = 1;
212 preped->size = strlen(in_out_buffer)+1;
213
214 /* acquire the lock on the cache again */
215 pth_mutex_acquire(&(cache->mutex), FALSE, NULL);
216
217 /* store the entry in the cache */
218 xhash_put(cache->hashtable, original, preped);
219
220 /* we're done, release the lock on the cache */
221 pth_mutex_release(&(cache->mutex));
222 } else {
223 /* we don't need the copy of the key, if there is no memory to store it */
224 free(original);
225 }
226 } else {
227 /* we don't need the copy of the original value */
228 if (original != NULL)
229 free(original);
230 }
231 }
232
233 return result;
234 }
235
236 /**
237 * free a single stringprep cache
238 *
239 * @param cache the cache to free
240 */
241 void _jid_stop_single_cache(_jid_prep_cache_t *cache) {
242 if (*cache == NULL)
243 return;
244
245 _jid_clean_single_cache(*cache, time(NULL));
246
247 pth_mutex_acquire(&((*cache)->mutex), FALSE, NULL);
248 xhash_free((*cache)->hashtable);
249
250 free(*cache);
251
252 *cache = NULL;
253 }
254
255 /**
256 * init a single stringprep cache
257 *
258 * @param cache the cache to init
259 * @param prime the prime used to init the hashtable
260 * @param profile profile used to prepare the strings
261 */
262 void _jid_init_single_cache(_jid_prep_cache_t *cache, int prime, const Stringprep_profile *profile) {
263 /* do not init a cache twice */
264 if (*cache == NULL) {
265 *cache = (_jid_prep_cache_t)malloc(sizeof(struct _jid_prep_cache_st));
266 pth_mutex_init(&((*cache)->mutex));
267 (*cache)->hashtable = xhash_new(prime);
268 (*cache)->profile = profile;
269 }
270 }
271
272 /**
273 * free the stringprep caches
274 */
275 void jid_stop_caching() {
276 _jid_stop_single_cache(&_jid_prep_cache_node);
277 _jid_stop_single_cache(&_jid_prep_cache_domain);
278 _jid_stop_single_cache(&_jid_prep_cache_resource);
279 }
280
281 /**
282 * init the stringprep caches
283 * (do not call this twice at the same time, we do not have the mutexes yet)
284 */
285 void jid_init_cache() {
286 /* init the nodeprep cache */
287 _jid_init_single_cache(&_jid_prep_cache_node, 2003, stringprep_xmpp_nodeprep);
288
289 /* init the nameprep cache (domains) */
290 _jid_init_single_cache(&_jid_prep_cache_domain, 2003, stringprep_nameprep);
291
292 /* init the resourceprep cache */
293 _jid_init_single_cache(&_jid_prep_cache_resource, 2003, stringprep_xmpp_resourceprep);
294 }
295
296 /**
297 * nameprep the domain identifier in a JID and check if it is valid
298 *
299 * @param jid data structure holding the JID
300 * @return 0 if JID is valid, non zero otherwise
301 */
302 int _jid_safe_domain(jid id) {
303 int result=0;
304
305 /* there must be a domain identifier */
306 if (j_strlen(id->server) == 0)
307 return 1;
308
309 /* nameprep the domain identifier */
310 result = _jid_cached_stringprep(id->server, strlen(id->server)+1, _jid_prep_cache_domain);
311 if (result == STRINGPREP_TOO_SMALL_BUFFER) {
312 /* nameprep wants to expand the string, e.g. conversion from &szlig; to ss */
313 size_t biggerbuffersize = 1024;
314 char *biggerbuffer = pmalloc(id->p, biggerbuffersize);
315 if (biggerbuffer == NULL)
316 return 1;
317 strcpy(biggerbuffer, id->server);
318 result = _jid_cached_stringprep(biggerbuffer, biggerbuffersize, _jid_prep_cache_domain);
319 id->server = biggerbuffer;
320 }
321 if (result != STRINGPREP_OK)
322 return 1;
323
324 /* the namepreped domain must not be longer than 1023 bytes */
325 if (j_strlen(id->server) > 1023)
326 return 1;
327
328 /* if nothing failed, the domain is valid */
329 return 0;
330 }
331
332 /**
333 * nodeprep the node identifier in a JID and check if it is valid
334 *
335 * @param jid data structure holding the JID
336 * @return 0 if JID is valid, non zero otherwise
337 */
338 int _jid_safe_node(jid id) {
339 int result=0;
340
341 /* it is valid to have no node identifier in the JID */
342 if (id->user == NULL)
343 return 0;
344
345 /* nodeprep */
346 result = _jid_cached_stringprep(id->user, strlen(id->user)+1, _jid_prep_cache_node);
347 if (result == STRINGPREP_TOO_SMALL_BUFFER) {
348 /* nodeprep wants to expand the string, e.g. conversion from &szlig; to ss */
349 size_t biggerbuffersize = 1024;
350 char *biggerbuffer = pmalloc(id->p, biggerbuffersize);
351 if (biggerbuffer == NULL)
352 return 1;
353 strcpy(biggerbuffer, id->user);
354 result = _jid_cached_stringprep(biggerbuffer, biggerbuffersize, _jid_prep_cache_node);
355 id->user = biggerbuffer;
356 }
357 if (result != STRINGPREP_OK)
358 return 1;
359
360 /* the nodepreped node must not be longer than 1023 bytes */
361 if (j_strlen(id->user) > 1023)
362 return 1;
363
364 /* if nothing failed, the node is valid */
365 return 0;
366 }
367
368 /**
369 * resourceprep the resource identifier in a JID and check if it is valid
370 *
371 * @param jid data structure holding the JID
372 * @return 0 if JID is valid, non zero otherwise
373 */
374 int _jid_safe_resource(jid id) {
375 int result=0;
376
377 /* it is valid to have no resource identifier in the JID */
378 if (id->resource == NULL)
379 return 0;
380
381 /* resource prep the resource identifier */
382 result = _jid_cached_stringprep(id->resource, strlen(id->resource)+1, _jid_prep_cache_resource);
383 if (result == STRINGPREP_TOO_SMALL_BUFFER) {
384 /* resourceprep wants to expand the string, e.g. conversion from &szlig; to ss */
385 size_t biggerbuffersize = 1024;
386 char *biggerbuffer = pmalloc(id->p, biggerbuffersize);
387 if (biggerbuffer == NULL)
388 return 1;
389 strcpy(biggerbuffer, id->resource);
390 result = _jid_cached_stringprep(id->resource, strlen(id->resource)+1, _jid_prep_cache_resource);
391 id->resource = biggerbuffer;
392 }
393 if (result != STRINGPREP_OK)
394 return 1;
395
396 /* the resourcepreped node must not be longer than 1023 bytes */
397 if (j_strlen(id->resource) > 1023)
398 return 1;
399
400 /* if nothing failed, the resource is valid */
401 return 0;
402
403 }
404
405 #else /* no LIBIDN */
406
407 /**
408 * check if the domain identifier in a JID is valid
409 *
410 * @param jid data structure holding the JID
411 * @return 0 if domain is valid, non zero otherwise
412 */
413 int _jid_safe_domain(jid id) {
24 char *str; 414 char *str;
25 415
26 if(strlen(id->server) == 0 || strlen(id->server) > 255) 416 /* there must be a domain identifier */
27 return NULL; 417 if (j_strlen(id->server) == 0)
418 return 1;
419
420 /* and it must not be longer than 1023 bytes */
421 if (strlen(id->server) > 1023)
422 return 1;
28 423
29 /* lowercase the hostname, make sure it's valid characters */ 424 /* lowercase the hostname, make sure it's valid characters */
30 for(str = id->server; *str != '\0'; str++) 425 for(str = id->server; *str != '\0'; str++)
31 { 426 {
32 *str = tolower(*str); 427 *str = tolower(*str);
33 if(!(isalnum(*str) || *str == '.' || *str == '-' || *str == '_')) return NULL; 428 if(!(isalnum(*str) || *str == '.' || *str == '-' || *str == '_')) return 1;
34 } 429 }
35 430
36 /* cut off the user */ 431 /* otherwise it's okay as far as we can tell without LIBIDN */
37 if(id->user != NULL && strlen(id->user) > 64) 432 return 0;
38 id->user[64] = '\0'; 433 }
434
435 /**
436 * check if the node identifier in a JID is valid
437 *
438 * @param jid data structure holding the JID
439 * @return 0 if node is valid, non zero otherwise
440 */
441 int _jid_safe_node(jid id) {
442 char *str;
443
444 /* node identifiers may not be longer than 1023 bytes */
445 if (j_strlen(id->user) > 1023)
446 return 1;
39 447
40 /* check for low and invalid ascii characters in the username */ 448 /* check for low and invalid ascii characters in the username */
41 if(id->user != NULL) 449 if(id->user != NULL)
42 for(str = id->user; *str != '\0'; str++) 450 for(str = id->user; *str != '\0'; str++)
43 if(*str <= 32 || *str == ':' || *str == '@' || *str == '<' || *str == '>' || *str == '\'' || *str == '"' || *str == '&') return NULL; 451 if(*str <= 32 || *str == ':' || *str == '@' || *str == '<' || *str == '>' || *str == '\'' || *str == '"' || *str == '&') return 1;
452
453 /* otherwise it's okay as far as we can tell without LIBIDN */
454 return 0;
455 }
456
457 /**
458 * check if the resource identifier in a JID is valid
459 *
460 * @param jid data structure holding the JID
461 * @return 0 if resource is valid, non zero otherwise
462 */
463 int _jid_safe_resource(jid id) {
464 /* resources may not be longer than 1023 bytes */
465 if (j_strlen(id->resource) > 1023)
466 return 1;
467
468 /* otherwise it's okay as far as we can tell without LIBIDN */
469 return 0;
470 }
471
472 #endif
473
474 /**
475 * nodeprep/nameprep/resourceprep the JID and check if it is valid
476 *
477 * @param jid data structure holding the JID
478 * @return NULL if the JID is invalid, pointer to the jid otherwise
479 */
480 jid jid_safe(jid id)
481 {
482 if (_jid_safe_domain(id))
483 return NULL;
484 if (_jid_safe_node(id))
485 return NULL;
486 if (_jid_safe_resource(id))
487 return NULL;
44 488
45 return id; 489 return id;
46 } 490 }
47 491
48 jid jid_new(pool p, char *idstr) 492 jid jid_new(pool p, char *idstr)
49 { 493 {
50 char *server, *resource, *type, *str; 494 char *server, *resource, *type, *str;
51 jid id; 495 jid id;
52 496
53 if(p == NULL || idstr == NULL || strlen(idstr) == 0) 497 if(p == NULL || idstr == NULL || strlen(idstr) == 0)
54 return NULL; 498 return NULL;
55 499
56 /* user@server/resource */ 500 /* user@server/resource */
57 501
58 str = pstrdup(p, idstr); 502 str = pstrdup(p, idstr);
59 503
60 id = pmalloc(p,sizeof(struct jid_struct)); 504 id = pmalloco(p,sizeof(struct jid_struct));
61 id->full = id->server = id->user = id->resource = NULL;
62 id->p = p; 505 id->p = p;
63 id->next = NULL;
64 506
65 resource = strstr(str,"/"); 507 resource = strstr(str,"/");
66 if(resource != NULL) 508 if(resource != NULL)
67 { 509 {
68 *resource = '\0'; 510 *resource = '\0';
69 ++resource; 511 ++resource;
70 if(strlen(resource) > 0) 512 if(strlen(resource) > 0)
71 id->resource = resource; 513 id->resource = resource;
72 }else{ 514 }else{
73 resource = str + strlen(str); /* point to end */ 515 resource = str + strlen(str); /* point to end */
74 } 516 }
75 517
76 type = strstr(str,":"); 518 type = strstr(str,":");
77 if(type != NULL && type < resource) 519 if(type != NULL && type < resource)
78 { 520 {
79 *type = '\0'; 521 *type = '\0';
80 ++type; 522 ++type;
81 str = type; /* ignore the type: prefix */ 523 str = type; /* ignore the type: prefix */
82 } 524 }
83 525
84 server = strstr(str,"@"); 526 server = strstr(str,"@");
85 if(server == NULL || server > resource) 527 if(server == NULL || server > resource)
86 { /* if there's no @, it's just the server address */ 528 { /* if there's no @, it's just the server address */
87 id->server = str; 529 id->server = str;
88 }else{ 530 }else{
89 *server = '\0'; 531 *server = '\0';
90 ++server; 532 ++server;
91 id->server = server; 533 id->server = server;
92 if(strlen(str) > 0) 534 if(strlen(str) > 0)
93 id->user = str; 535 id->user = str;
94 } 536 }
95 537
96 return jid_safe(id); 538 return jid_safe(id);
97 } 539 }
98 540
99 void jid_set(jid id, char *str, int item) 541 void jid_set(jid id, char *str, int item)
100 { 542 {
101 char *old; 543 char *old;
102 544
103 if(id == NULL) 545 if(id == NULL)
104 return; 546 return;
105 547
106 /* invalidate the cached copy */ 548 /* invalidate the cached copy */
107 id->full = NULL; 549 id->full = NULL;
108 550
109 switch(item) 551 switch(item)
110 { 552 {
111 case JID_RESOURCE: 553 case JID_RESOURCE:
112 if(str != NULL && strlen(str) != 0) 554 old = id->resource;
113 id->resource = pstrdup(id->p, str); 555 if(str != NULL && strlen(str) != 0)
114 else 556 id->resource = pstrdup(id->p, str);
115 id->resource = NULL; 557 else
116 break; 558 id->resource = NULL;
559 if(_jid_safe_resource(id))
560 id->resource = old; /* revert if invalid */
561 break;
117 case JID_USER: 562 case JID_USER:
118 old = id->user; 563 old = id->user;
119 if(str != NULL && strlen(str) != 0) 564 if(str != NULL && strlen(str) != 0)
120 id->user = pstrdup(id->p, str); 565 id->user = pstrdup(id->p, str);
121 else 566 else
122 id->user = NULL; 567 id->user = NULL;
123 if(jid_safe(id) == NULL) 568 if(_jid_safe_node(id))
124 id->user = old; /* revert if invalid */ 569 id->user = old; /* revert if invalid */
125 break; 570 break;
126 case JID_SERVER: 571 case JID_SERVER:
127 old = id->server; 572 old = id->server;
128 id->server = pstrdup(id->p, str); 573 id->server = pstrdup(id->p, str);
129 if(jid_safe(id) == NULL) 574 if(_jid_safe_domain(id))
130 id->server = old; /* revert if invalid */ 575 id->server = old; /* revert if invalid */
131 break; 576 break;
132 } 577 }
133 578
134 } 579 }
135 580
136 char *jid_full(jid id) 581 char *jid_full(jid id)
137 { 582 {
138 spool s; 583 spool s;
139 584
140 if(id == NULL) 585 if(id == NULL)
141 return NULL; 586 return NULL;
142 587
143 /* use cached copy */ 588 /* use cached copy */
144 if(id->full != NULL) 589 if(id->full != NULL)
145 return id->full; 590 return id->full;
146 591
147 s = spool_new(id->p); 592 s = spool_new(id->p);
148 593
149 if(id->user != NULL) 594 if(id->user != NULL)
150 spooler(s, id->user,"@",s); 595 spooler(s, id->user,"@",s);
151 596
152 spool_add(s, id->server); 597 spool_add(s, id->server);
153 598
154 if(id->resource != NULL) 599 if(id->resource != NULL)
155 spooler(s, "/",id->resource,s); 600 spooler(s, "/",id->resource,s);
156 601
157 id->full = spool_print(s); 602 id->full = spool_print(s);
158 return id->full; 603 return id->full;
159 } 604 }
160 605
175 x = _xmlnode_new(id->p, cur, NTYPE_TAG); 620 x = _xmlnode_new(id->p, cur, NTYPE_TAG);
176 621
177 cur = qmark; 622 cur = qmark;
178 while(cur != '\0') 623 while(cur != '\0')
179 { 624 {
180 eq = strstr(cur, "="); 625 eq = strstr(cur, "=");
181 if(eq == NULL) break; 626 if(eq == NULL) break;
182 *eq = '\0'; 627 *eq = '\0';
183 eq++; 628 eq++;
184 629
185 amp = strstr(eq, "&"); 630 amp = strstr(eq, "&");
186 if(amp != NULL) 631 if(amp != NULL)
187 { 632 {
188 *amp = '\0'; 633 *amp = '\0';
189 amp++; 634 amp++;
190 } 635 }
191 636
192 xmlnode_put_attrib(x,cur,eq); 637 xmlnode_put_attrib(x,cur,eq);
193 638
194 if(amp != NULL) 639 if(amp != NULL)
195 cur = amp; 640 cur = amp;
196 else 641 else
197 break; 642 break;
198 } 643 }
199 644
200 return x; 645 return x;
201 } 646 }
202 647
215 } 660 }
216 661
217 int jid_cmp(jid a, jid b) 662 int jid_cmp(jid a, jid b)
218 { 663 {
219 if(a == NULL || b == NULL) 664 if(a == NULL || b == NULL)
220 return -1; 665 return -1;
221 666
222 if(_jid_nullstrcmp(a->resource, b->resource) != 0) return -1; 667 if(_jid_nullstrcmp(a->resource, b->resource) != 0) return -1;
223 if(_jid_nullstrcasecmp(a->user, b->user) != 0) return -1; 668 if(_jid_nullstrcasecmp(a->user, b->user) != 0) return -1;
224 if(_jid_nullstrcmp(a->server, b->server) != 0) return -1; 669 if(_jid_nullstrcmp(a->server, b->server) != 0) return -1;
225 670
228 673
229 /* suggested by Anders Qvist <quest@valdez.netg.se> */ 674 /* suggested by Anders Qvist <quest@valdez.netg.se> */
230 int jid_cmpx(jid a, jid b, int parts) 675 int jid_cmpx(jid a, jid b, int parts)
231 { 676 {
232 if(a == NULL || b == NULL) 677 if(a == NULL || b == NULL)
233 return -1; 678 return -1;
234 679
235 if(parts & JID_RESOURCE && _jid_nullstrcmp(a->resource, b->resource) != 0) return -1; 680 if(parts & JID_RESOURCE && _jid_nullstrcmp(a->resource, b->resource) != 0) return -1;
236 if(parts & JID_USER && _jid_nullstrcasecmp(a->user, b->user) != 0) return -1; 681 if(parts & JID_USER && _jid_nullstrcasecmp(a->user, b->user) != 0) return -1;
237 if(parts & JID_SERVER && _jid_nullstrcmp(a->server, b->server) != 0) return -1; 682 if(parts & JID_SERVER && _jid_nullstrcmp(a->server, b->server) != 0) return -1;
238 683
243 jid jid_append(jid a, jid b) 688 jid jid_append(jid a, jid b)
244 { 689 {
245 jid next; 690 jid next;
246 691
247 if(a == NULL) 692 if(a == NULL)
248 return NULL; 693 return NULL;
249 694
250 if(b == NULL) 695 if(b == NULL)
251 return a; 696 return a;
252 697
253 next = a; 698 next = a;
254 while(next != NULL) 699 while(next != NULL)
255 { 700 {
256 /* check for dups */ 701 /* check for dups */
257 if(jid_cmp(next,b) == 0) 702 if(jid_cmp(next,b) == 0)
258 break; 703 break;
259 if(next->next == NULL) 704 if(next->next == NULL)
260 next->next = jid_new(a->p,jid_full(b)); 705 next->next = jid_new(a->p,jid_full(b));
261 next = next->next; 706 next = next->next;
262 } 707 }
263 return a; 708 return a;
264 } 709 }
265 710
266 xmlnode jid_nodescan(jid id, xmlnode x) 711 xmlnode jid_nodescan(jid id, xmlnode x)
272 if(id == NULL || xmlnode_get_firstchild(x) == NULL) return NULL; 717 if(id == NULL || xmlnode_get_firstchild(x) == NULL) return NULL;
273 718
274 p = pool_new(); 719 p = pool_new();
275 for(cur = xmlnode_get_firstchild(x); cur != NULL; cur = xmlnode_get_nextsibling(cur)) 720 for(cur = xmlnode_get_firstchild(x); cur != NULL; cur = xmlnode_get_nextsibling(cur))
276 { 721 {
277 if(xmlnode_get_type(cur) != NTYPE_TAG) continue; 722 if(xmlnode_get_type(cur) != NTYPE_TAG) continue;
278 723
279 tmp = jid_new(p,xmlnode_get_attrib(cur,"jid")); 724 tmp = jid_new(p,xmlnode_get_attrib(cur,"jid"));
280 if(tmp == NULL) continue; 725 if(tmp == NULL) continue;
281 726
282 if(jid_cmp(tmp,id) == 0) break; 727 if(jid_cmp(tmp,id) == 0) break;
283 } 728 }
284 pool_free(p); 729 pool_free(p);
285 730
286 return cur; 731 return cur;
287 } 732 }
733
734 jid jid_user(jid a)
735 {
736 jid ret;
737
738 if(a == NULL || a->resource == NULL) return a;
739
740 ret = pmalloco(a->p,sizeof(struct jid_struct));
741 ret->p = a->p;
742 ret->user = a->user;
743 ret->server = a->server;
744
745 return ret;
746 }