Mercurial > ~mikael > mcabber > hg
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 ß 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 ß 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 ß 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 } |