fixed build error
[public/netxms.git] / src / libstrophe / stanza.c
1 /* stanza.c
2 ** strophe XMPP client library -- XMPP stanza object and utilities
3 **
4 ** Copyright (C) 2005-2009 Collecta, Inc.
5 **
6 ** This software is provided AS-IS with no warranty, either express
7 ** or implied.
8 **
9 ** This software is distributed under license and may not be copied,
10 ** modified or distributed except as expressly authorized under the
11 ** terms of the license contained in the file LICENSE.txt in this
12 ** distribution.
13 */
14
15 /** @file
16 * Stanza creation and manipulation.
17 */
18
19 /** @defgroup Stanza Stanza creation and manipulation
20 */
21
22 #include <nms_common.h>
23 #include <strophe.h>
24 #include "common.h"
25 #include "hash.h"
26
27 #ifdef _WIN32
28 #define inline __inline
29 #endif
30
31 /** Create a stanza object.
32 * This function allocates and initializes and blank stanza object.
33 * The stanza will have a reference count of one, so the caller does not
34 * need to clone it.
35 *
36 * @param ctx a Strophe context object
37 *
38 * @return a stanza object
39 *
40 * @ingroup Stanza
41 */
42 xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx)
43 {
44 xmpp_stanza_t *stanza;
45
46 stanza = xmpp_alloc(ctx, sizeof(xmpp_stanza_t));
47 if (stanza != NULL) {
48 stanza->ref = 1;
49 stanza->ctx = ctx;
50 stanza->type = XMPP_STANZA_UNKNOWN;
51 stanza->prev = NULL;
52 stanza->next = NULL;
53 stanza->children = NULL;
54 stanza->parent = NULL;
55 stanza->data = NULL;
56 stanza->attributes = NULL;
57 }
58
59 return stanza;
60 }
61
62 /** Clone a stanza object.
63 * This function increments the reference count of the stanza object.
64 *
65 * @param stanza a Strophe stanza object
66 *
67 * @return the stanza object with it's reference count incremented
68 *
69 * @ingroup Stanza
70 */
71 xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t * const stanza)
72 {
73 stanza->ref++;
74
75 return stanza;
76 }
77
78 /** Copy a stanza and its children.
79 * This function copies a stanza along with all its children and returns
80 * the new stanza and children with a reference count of 1. The returned
81 * stanza will have no parent and no siblings. This function is useful
82 * for extracting a child stanza for inclusion in another tree.
83 *
84 * @param stanza a Strophe stanza object
85 *
86 * @return a new Strophe stanza object
87 *
88 * @ingroup Stanza
89 */
90 xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
91 {
92 xmpp_stanza_t *copy, *child, *copychild, *tail;
93 hash_iterator_t *iter;
94 const char *key;
95 void *val;
96
97 copy = xmpp_stanza_new(stanza->ctx);
98 if (!copy) goto copy_error;
99
100 copy->type = stanza->type;
101
102 if (stanza->data) {
103 copy->data = xmpp_strdup(stanza->ctx, stanza->data);
104 if (!copy->data) goto copy_error;
105 }
106
107 if (stanza->attributes) {
108 copy->attributes = hash_new(stanza->ctx, 8, xmpp_free);
109 if (!copy->attributes) goto copy_error;
110 iter = hash_iter_new(stanza->attributes);
111 if (!iter) { printf("DEBUG HERE\n"); goto copy_error; }
112 while ((key = hash_iter_next(iter))) {
113 val = xmpp_strdup(stanza->ctx,
114 (char *)hash_get(stanza->attributes, key));
115 if (!val) goto copy_error;
116
117 if (hash_add(copy->attributes, key, val))
118 goto copy_error;
119 }
120 hash_iter_release(iter);
121 }
122
123 tail = copy->children;
124 for (child = stanza->children; child; child = child->next) {
125 copychild = xmpp_stanza_copy(child);
126 if (!copychild) goto copy_error;
127 copychild->parent = copy;
128
129 if (tail) {
130 copychild->prev = tail;
131 tail->next = copychild;
132 } else
133 copy->children = copychild;
134 tail = copychild;
135 }
136
137 return copy;
138
139 copy_error:
140 /* release all the hitherto allocated memory */
141 if (copy) xmpp_stanza_release(copy);
142 return NULL;
143 }
144
145 /** Release a stanza object and all of its children.
146 * This function releases a stanza object and potentially all of its
147 * children, which may cause the object(s) to be freed.
148 *
149 * @param stanza a Strophe stanza object
150 *
151 * @return TRUE if the object was freed and FALSE otherwise
152 *
153 * @ingroup Stanza
154 */
155 int xmpp_stanza_release(xmpp_stanza_t * const stanza)
156 {
157 int released = 0;
158 xmpp_stanza_t *child, *tchild;
159
160 /* release stanza */
161 if (stanza->ref > 1)
162 {
163 stanza->ref--;
164 }
165 else
166 {
167 /* release all children */
168 child = stanza->children;
169 while (child)
170 {
171 tchild = child;
172 child = child->next;
173 xmpp_stanza_release(tchild);
174 }
175
176 if (stanza->attributes)
177 hash_release(stanza->attributes);
178 if (stanza->data)
179 xmpp_free(stanza->ctx, stanza->data);
180 xmpp_free(stanza->ctx, stanza);
181 released = 1;
182 }
183 return released;
184 }
185
186 /** Determine if a stanza is a text node.
187 *
188 * @param stanza a Strophe stanza object
189 *
190 * @return TRUE if the stanza is a text node, FALSE otherwise
191 *
192 * @ingroup Stanza
193 */
194 int xmpp_stanza_is_text(xmpp_stanza_t * const stanza)
195 {
196 return (stanza && stanza->type == XMPP_STANZA_TEXT);
197 }
198
199 /** Determine if a stanza is a tag node.
200 *
201 * @param stanza a Strophe stanza object
202 *
203 * @return TRUE if the stanza is a tag node, FALSE otherwise
204 *
205 * @ingroup Stanza
206 */
207 int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza)
208 {
209 return (stanza && stanza->type == XMPP_STANZA_TAG);
210 }
211
212 /* Escape a string with for use in a XML text node or attribute. Assumes that
213 * the input string is encoded in UTF-8. On sucess, returns a pointer to a
214 * buffer with the resulting data which must be xmpp_free()'d by the caller.
215 * On failure, returns NULL.
216 */
217
218 static char *_escape_xml(xmpp_ctx_t * const ctx, char *text)
219 {
220 size_t len = 0;
221 char *src;
222 char *dst;
223 char *buf;
224 for (src = text; *src != '\0'; src++) {
225 switch (*src) {
226 case '<': /* "&lt;" */
227 case '>': /* "&gt;" */
228 len += 4;
229 break;
230 case '&': /* "&amp;" */
231 len += 5;
232 break;
233 case '"':
234 len += 6; /*"&quot;" */
235 break;
236 default:
237 len++;
238 }
239 }
240 if ((buf = xmpp_alloc(ctx, (len+1) * sizeof(char))) == NULL)
241 return NULL; /* Error */
242 dst = buf;
243 for (src = text; *src != '\0'; src++) {
244 switch (*src) {
245 case '<':
246 strcpy(dst, "&lt;");
247 dst += 4;
248 break;
249 case '>':
250 strcpy(dst, "&gt;");
251 dst += 4;
252 break;
253 case '&':
254 strcpy(dst, "&amp;");
255 dst += 5;
256 break;
257 case '"':
258 strcpy(dst, "&quot;");
259 dst += 6;
260 break;
261 default:
262 *dst = *src;
263 dst++;
264 }
265 }
266 *dst = '\0';
267 return buf;
268 }
269
270 /* small helper function */
271 static inline void _render_update(int *written, const int length,
272 const int lastwrite,
273 size_t *left, char **ptr)
274 {
275 *written += lastwrite;
276
277 if (*written > length) {
278 *left = 0;
279 *ptr = NULL;
280 } else {
281 *left -= lastwrite;
282 *ptr = &(*ptr)[lastwrite];
283 }
284 }
285
286 /* always returns number of bytes written or that would have been
287 * written if the buffer was large enough
288 * return values < 0 indicate some error occured,
289 * and return values > buflen indicate buffer was not large enough
290 */
291 static int _render_stanza_recursive(xmpp_stanza_t *stanza,
292 char * const buf, size_t const buflen)
293 {
294 char *ptr = buf;
295 size_t left = buflen;
296 int ret, written;
297 xmpp_stanza_t *child;
298 hash_iterator_t *iter;
299 const char *key;
300 char *tmp;
301
302 written = 0;
303
304 if (stanza->type == XMPP_STANZA_UNKNOWN) return XMPP_EINVOP;
305
306 if (stanza->type == XMPP_STANZA_TEXT) {
307 if (!stanza->data) return XMPP_EINVOP;
308
309 tmp = _escape_xml(stanza->ctx, stanza->data);
310 if (tmp == NULL) return XMPP_EMEM;
311 ret = xmpp_snprintf(ptr, left, "%s", tmp);
312 xmpp_free(stanza->ctx, tmp);
313 if (ret < 0) return XMPP_EMEM;
314 _render_update(&written, buflen, ret, &left, &ptr);
315 } else { /* stanza->type == XMPP_STANZA_TAG */
316 if (!stanza->data) return XMPP_EINVOP;
317
318 /* write begining of tag and attributes */
319 ret = xmpp_snprintf(ptr, left, "<%s", stanza->data);
320 if (ret < 0) return XMPP_EMEM;
321 _render_update(&written, buflen, ret, &left, &ptr);
322
323 if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) {
324 iter = hash_iter_new(stanza->attributes);
325 while ((key = hash_iter_next(iter))) {
326 tmp = _escape_xml(stanza->ctx,
327 (char *)hash_get(stanza->attributes, key));
328 if (tmp == NULL) return XMPP_EMEM;
329 ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, tmp);
330 xmpp_free(stanza->ctx, tmp);
331 if (ret < 0) return XMPP_EMEM;
332 _render_update(&written, buflen, ret, &left, &ptr);
333 }
334 hash_iter_release(iter);
335 }
336
337 if (!stanza->children) {
338 /* write end if singleton tag */
339 ret = xmpp_snprintf(ptr, left, "/>");
340 if (ret < 0) return XMPP_EMEM;
341 _render_update(&written, buflen, ret, &left, &ptr);
342 } else {
343 /* this stanza has child stanzas */
344
345 /* write end of start tag */
346 ret = xmpp_snprintf(ptr, left, ">");
347 if (ret < 0) return XMPP_EMEM;
348 _render_update(&written, buflen, ret, &left, &ptr);
349
350 /* iterate and recurse over child stanzas */
351 child = stanza->children;
352 while (child) {
353 ret = _render_stanza_recursive(child, ptr, left);
354 if (ret < 0) return ret;
355
356 _render_update(&written, buflen, ret, &left, &ptr);
357
358 child = child->next;
359 }
360
361 /* write end tag */
362 ret = xmpp_snprintf(ptr, left, "</%s>", stanza->data);
363 if (ret < 0) return XMPP_EMEM;
364
365 _render_update(&written, buflen, ret, &left, &ptr);
366 }
367 }
368
369 return written;
370 }
371
372 /** Render a stanza object to text.
373 * This function renders a given stanza object, along with its
374 * children, to text. The text is returned in an allocated,
375 * null-terminated buffer. It starts by allocating a 1024 byte buffer
376 * and reallocates more memory if that is not large enough.
377 *
378 * @param stanza a Strophe stanza object
379 * @param buf a reference to a string pointer
380 * @param buflen a reference to a size_t
381 *
382 * @return 0 on success (XMPP_EOK), and a number less than 0 on failure
383 * (XMPP_EMEM, XMPP_EINVOP)
384 *
385 * @ingroup Stanza
386 */
387 int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
388 char ** const buf,
389 size_t * const buflen)
390 {
391 char *buffer, *tmp;
392 size_t length;
393 int ret;
394
395 /* allocate a default sized buffer and attempt to render */
396 length = 1024;
397 buffer = xmpp_alloc(stanza->ctx, length);
398 if (!buffer) {
399 *buf = NULL;
400 *buflen = 0;
401 return XMPP_EMEM;
402 }
403
404 ret = _render_stanza_recursive(stanza, buffer, length - 1);
405 if (ret < 0) return ret;
406
407 if (ret > length - 1) {
408 tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1);
409 if (!tmp) {
410 xmpp_free(stanza->ctx, buffer);
411 *buf = NULL;
412 *buflen = 0;
413 return XMPP_EMEM;
414 }
415 length = ret + 1;
416 buffer = tmp;
417
418 ret = _render_stanza_recursive(stanza, buffer, length);
419 if (ret > length - 1) return XMPP_EMEM;
420 }
421
422 buffer[length - 1] = 0;
423
424 *buf = buffer;
425 *buflen = ret;
426
427 return XMPP_EOK;
428 }
429
430 /** Set the name of a stanza.
431 *
432 * @param stanza a Strophe stanza object
433 * @param name a string with the name of the stanza
434 *
435 * @return XMPP_EOK on success, a number less than 0 on failure (XMPP_EMEM,
436 * XMPP_EINVOP)
437 *
438 * @ingroup Stanza
439 */
440 int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
441 const char * const name)
442 {
443 if (stanza->type == XMPP_STANZA_TEXT) return XMPP_EINVOP;
444
445 if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
446
447 stanza->type = XMPP_STANZA_TAG;
448 stanza->data = xmpp_strdup(stanza->ctx, name);
449
450 return XMPP_EOK;
451 }
452
453 /** Get the stanza name.
454 * This function returns a pointer to the stanza name. If the caller needs
455 * to store this data, it must make a copy.
456 *
457 * @param stanza a Strophe stanza object
458 *
459 * @return a string with the stanza name
460 *
461 * @ingroup Stanza
462 */
463 char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza)
464 {
465 if (stanza->type == XMPP_STANZA_TEXT) return NULL;
466 return stanza->data;
467 }
468
469 /** Count the attributes in a stanza object.
470 *
471 * @param stanza a Strophe stanza object
472 *
473 * @return the number of attributes for the stanza object
474 *
475 * @ingroup Stanza
476 */
477 int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza)
478 {
479 if (stanza->attributes == NULL) {
480 return 0;
481 }
482
483 return hash_num_keys(stanza->attributes);
484 }
485
486 /** Get all attributes for a stanza object.
487 * This function populates the array with attributes from the stanza. The
488 * attr array will be in the format: attr[i] = attribute name,
489 * attr[i+1] = attribute value.
490 *
491 * @param stanza a Strophe stanza object
492 * @param attr the string array to populate
493 * @param attrlen the size of the array
494 *
495 * @return the number of slots used in the array, which will be 2 times the
496 * number of attributes in the stanza
497 *
498 * @ingroup Stanza
499 */
500 int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
501 const char **attr, int attrlen)
502 {
503 hash_iterator_t *iter;
504 const char *key;
505 int num = 0;
506
507 if (stanza->attributes == NULL) {
508 return 0;
509 }
510
511 iter = hash_iter_new(stanza->attributes);
512 while ((key = hash_iter_next(iter)) != NULL && attrlen) {
513 attr[num++] = key;
514 attrlen--;
515 if (attrlen == 0) {
516 hash_iter_release(iter);
517 return num;
518 }
519 attr[num++] = hash_get(stanza->attributes, key);
520 attrlen--;
521 if (attrlen == 0) {
522 hash_iter_release(iter);
523 return num;
524 }
525 }
526
527 hash_iter_release(iter);
528 return num;
529 }
530
531 /** Set an attribute for a stanza object.
532 *
533 * @param stanza a Strophe stanza object
534 * @param key a string with the attribute name
535 * @param value a string with the attribute value
536 *
537 * @return XMPP_EOK (0) on success or a number less than 0 on failure
538 *
539 * @ingroup Stanza
540 */
541 int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
542 const char * const key,
543 const char * const value)
544 {
545 char *val;
546
547 if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP;
548
549 if (!stanza->attributes) {
550 stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free);
551 if (!stanza->attributes) return XMPP_EMEM;
552 }
553
554 val = xmpp_strdup(stanza->ctx, value);
555 if (!val) return XMPP_EMEM;
556
557 hash_add(stanza->attributes, key, val);
558
559 return XMPP_EOK;
560 }
561
562 /** Set the stanza namespace.
563 * This is a convenience function equivalent to calling:
564 * xmpp_stanza_set_attribute(stanza, "xmlns", ns);
565 *
566 * @param stanza a Strophe stanza object
567 * @param ns a string with the namespace
568 *
569 * @return XMPP_EOK (0) on success or a number less than 0 on failure
570 *
571 * @ingroup Stanza
572 */
573 int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza, const char * const ns)
574 {
575 return xmpp_stanza_set_attribute(stanza, "xmlns", ns);
576 }
577
578 /** Add a child stanza to a stanza object.
579 * This function clones the child and appends it to the stanza object's
580 * children.
581 *
582 * @param stanza a Strophe stanza object
583 * @param child the child stanza object
584 *
585 * @return XMPP_EOK (0) on success or a number less than 0 on failure
586 *
587 * @ingroup Stanza
588 */
589 int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
590 {
591 return xmpp_stanza_add_child_ex(stanza, child, TRUE);
592 }
593
594 /** Add a child stanza to a stanza object.
595 * This function clones the child and appends it to the stanza object's
596 * children.
597 *
598 * @param stanza a Strophe stanza object
599 * @param child the child stanza object
600 * @param do_clone TRUE to increase ref count of child (default for xmpp_stanza_add_child)
601 *
602 * @return XMPP_EOK (0) on success or a number less than 0 on failure
603 *
604 * @ingroup Stanza
605 */
606 int xmpp_stanza_add_child_ex(xmpp_stanza_t *stanza, xmpp_stanza_t *child, int do_clone)
607 {
608 xmpp_stanza_t *s;
609
610 /* get a reference to the child */
611 if (do_clone)
612 xmpp_stanza_clone(child);
613
614 child->parent = stanza;
615
616 if (!stanza->children)
617 stanza->children = child;
618 else {
619 s = stanza->children;
620 while (s->next) s = s->next;
621 s->next = child;
622 child->prev = s;
623 }
624
625 return XMPP_EOK;
626 }
627
628 /** Set the text data for a text stanza.
629 * This function copies the text given and sets the stanza object's text to
630 * it. Attempting to use this function on a stanza that has a name will
631 * fail with XMPP_EINVOP. This function takes the text as a null-terminated
632 * string.
633 *
634 * @param stanza a Strophe stanza object
635 * @param text a string with the text
636 *
637 * @return XMPP_EOK (0) on success or a number less than zero on failure
638 *
639 * @ingroup Stanza
640 */
641 int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
642 const char * const text)
643 {
644 if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
645
646 stanza->type = XMPP_STANZA_TEXT;
647
648 if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
649 stanza->data = xmpp_strdup(stanza->ctx, text);
650
651 return XMPP_EOK;
652 }
653
654 /** Set the text data for a text stanza.
655 * This function copies the text given and sets teh stanza object's text to
656 * it. Attempting to use this function on a stanza that has a name will
657 * fail with XMPP_EINVOP. This function takes the text as buffer and a length
658 * as opposed to a null-terminated string.
659 *
660 * @param stanza a Strophe stanza object
661 * @param text a buffer with the text
662 * @param size the length of the text
663 *
664 * @return XMPP_EOK (0) on success and a number less than 0 on failure
665 *
666 * @ingroup Stanza
667 */
668 int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
669 const char * const text,
670 const size_t size)
671 {
672 if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
673
674 stanza->type = XMPP_STANZA_TEXT;
675
676 if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
677 stanza->data = xmpp_alloc(stanza->ctx, size + 1);
678 if (!stanza->data) return XMPP_EMEM;
679
680 memcpy(stanza->data, text, size);
681 stanza->data[size] = 0;
682
683 return XMPP_EOK;
684 }
685
686 /** Get the 'id' attribute of the stanza object.
687 * This is a convenience function equivalent to:
688 * xmpp_stanza_get_attribute(stanza, "id");
689 *
690 * @param stanza a Strophe stanza object
691 *
692 * @return a string with the 'id' attribute value
693 *
694 * @ingroup Stanza
695 */
696 char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza)
697 {
698 if (stanza->type != XMPP_STANZA_TAG)
699 return NULL;
700
701 if (!stanza->attributes)
702 return NULL;
703
704 return (char *)hash_get(stanza->attributes, "id");
705 }
706
707 /** Get the namespace attribute of the stanza object.
708 * This is a convenience function equivalent to:
709 * xmpp_stanza_get_attribute(stanza, "xmlns");
710 *
711 * @param stanza a Strophe stanza object
712 *
713 * @return a string with the 'xmlns' attribute value
714 *
715 * @ingroup Stanza
716 */
717 char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza)
718 {
719 if (stanza->type != XMPP_STANZA_TAG)
720 return NULL;
721
722 if (!stanza->attributes)
723 return NULL;
724
725 return (char *)hash_get(stanza->attributes, "xmlns");
726 }
727
728 /** Get the 'type' attribute of the stanza object.
729 * This is a convenience function equivalent to:
730 * xmpp_stanza_get_attribute(stanza, "type");
731 *
732 * @param stanza a Strophe stanza object
733 *
734 * @return a string with the 'type' attribute value
735 *
736 * @ingroup Stanza
737 */
738 char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza)
739 {
740 if (stanza->type != XMPP_STANZA_TAG)
741 return NULL;
742
743 if (!stanza->attributes)
744 return NULL;
745
746 return (char *)hash_get(stanza->attributes, "type");
747 }
748
749 /** Get the first child of stanza with name.
750 * This function searches all the immediate children of stanza for a child
751 * stanza that matches the name. The first matching child is returned.
752 *
753 * @param stanza a Strophe stanza object
754 * @param name a string with the name to match
755 *
756 * @return the matching child stanza object or NULL if no match was found
757 *
758 * @ingroup Stanza
759 */
760 xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
761 const char * const name)
762 {
763 xmpp_stanza_t *child;
764
765 for (child = stanza->children; child; child = child->next) {
766 if (child->type == XMPP_STANZA_TAG &&
767 (strcmp(name, xmpp_stanza_get_name(child)) == 0))
768 break;
769 }
770
771 return child;
772 }
773
774 /** Get the first child of a stanza with a given namespace.
775 * This function searches all the immediate children of a stanza for a child
776 * stanza that matches the namespace provided. The first matching child
777 * is returned.
778 *
779 * @param stanza a Strophe stanza object
780 * @param ns a string with the namespace to match
781 *
782 * @return the matching child stanza object or NULL if no match was found
783 *
784 * @ingroup Stanza
785 */
786 xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
787 const char * const ns)
788 {
789 xmpp_stanza_t *child;
790
791 for (child = stanza->children; child; child = child->next) {
792 if (xmpp_stanza_get_ns(child) &&
793 strcmp(ns, xmpp_stanza_get_ns(child)) == 0)
794 break;
795 }
796
797 return child;
798 }
799
800 /** Get the list of children.
801 * This function returns the first child of the stanza object. The rest
802 * of the children can be obtained by calling xmpp_stanza_get_next() to
803 * iterate over the siblings.
804 *
805 * @param stanza a Strophe stanza object
806 *
807 * @return the first child stanza or NULL if there are no children
808 *
809 * @ingroup Stanza
810 */
811 xmpp_stanza_t *xmpp_stanza_get_children(xmpp_stanza_t * const stanza)
812 {
813 return stanza->children;
814 }
815
816 /** Get the next sibling of a stanza.
817 *
818 * @param stanza a Strophe stanza object
819 *
820 * @return the next sibling stanza or NULL if there are no more siblings
821 *
822 * @ingroup Stanza
823 */
824 xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t * const stanza)
825 {
826 return stanza->next;
827 }
828
829 /** Get the text data for a text stanza.
830 * This function copies the text data from a stanza and returns the new
831 * allocated string. The caller is responsible for freeing this string
832 * with xmpp_free().
833 *
834 * @param stanza a Strophe stanza object
835 *
836 * @return an allocated string with the text data
837 *
838 * @ingroup Stanza
839 */
840 char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
841 {
842 size_t len, clen;
843 xmpp_stanza_t *child;
844 char *text;
845
846 if (stanza->type == XMPP_STANZA_TEXT) {
847 if (stanza->data)
848 return xmpp_strdup(stanza->ctx, stanza->data);
849 else
850 return NULL;
851 }
852
853 len = 0;
854 for (child = stanza->children; child; child = child->next)
855 if (child->type == XMPP_STANZA_TEXT)
856 len += strlen(child->data);
857
858 if (len == 0) return NULL;
859
860 text = (char *)xmpp_alloc(stanza->ctx, len + 1);
861 if (!text) return NULL;
862
863 len = 0;
864 for (child = stanza->children; child; child = child->next)
865 if (child->type == XMPP_STANZA_TEXT) {
866 clen = strlen(child->data);
867 memcpy(&text[len], child->data, clen);
868 len += clen;
869 }
870
871 text[len] = 0;
872
873 return text;
874 }
875
876 /** Get the text data pointer for a text stanza.
877 * This function copies returns the raw pointer to the text data in the
878 * stanza. This should only be used in very special cases where the
879 * caller needs to translate the datatype as this will save a double
880 * allocation. The caller should not hold onto this pointer, and is
881 * responsible for allocating a copy if it needs one.
882 *
883 * @param stanza a Strophe stanza object
884 *
885 * @return an string pointer to the data or NULL
886 *
887 * @ingroup Stanza
888 */
889 char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza)
890 {
891 if (stanza->type == XMPP_STANZA_TEXT)
892 return stanza->data;
893 return NULL;
894 }
895
896 /** Set the 'id' attribute of a stanza.
897 *
898 * This is a convenience function for:
899 * xmpp_stanza_set_attribute(stanza, 'id', id);
900 *
901 * @param stanza a Strophe stanza object
902 * @param id a string containing the 'id' value
903 *
904 * @return XMPP_EOK (0) on success or a number less than 0 on failure
905 *
906 * @ingroup Stanza
907 */
908 int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
909 const char * const id)
910 {
911 return xmpp_stanza_set_attribute(stanza, "id", id);
912 }
913
914 /** Set the 'type' attribute of a stanza.
915 * This is a convenience function for:
916 * xmpp_stanza_set_attribute(stanza, 'type', type);
917 *
918 * @param stanza a Strophe stanza object
919 * @param type a string containing the 'type' value
920 *
921 * @return XMPP_EOK (0) on success or a number less than 0 on failure
922 *
923 * @ingroup Stanza
924 */
925 int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
926 const char * const type)
927 {
928 return xmpp_stanza_set_attribute(stanza, "type", type);
929 }
930
931 /** Get an attribute from a stanza.
932 * This function returns a pointer to the attribute value. If the caller
933 * wishes to save this value it must make its own copy.
934 *
935 * @param stanza a Strophe stanza object
936 * @param name a string containing attribute name
937 *
938 * @return a string with the attribute value or NULL on an error
939 *
940 * @ingroup Stanza
941 */
942 char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
943 const char * const name)
944 {
945 if (stanza->type != XMPP_STANZA_TAG)
946 return NULL;
947
948 if (!stanza->attributes)
949 return NULL;
950
951 return hash_get(stanza->attributes, name);
952 }