fixed memory leaks
[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, int do_clone)
590 {
591 xmpp_stanza_t *s;
592
593 /* get a reference to the child */
594 if (do_clone)
595 xmpp_stanza_clone(child);
596
597 child->parent = stanza;
598
599 if (!stanza->children)
600 stanza->children = child;
601 else {
602 s = stanza->children;
603 while (s->next) s = s->next;
604 s->next = child;
605 child->prev = s;
606 }
607
608 return XMPP_EOK;
609 }
610
611 /** Set the text data for a text stanza.
612 * This function copies the text given and sets the stanza object's text to
613 * it. Attempting to use this function on a stanza that has a name will
614 * fail with XMPP_EINVOP. This function takes the text as a null-terminated
615 * string.
616 *
617 * @param stanza a Strophe stanza object
618 * @param text a string with the text
619 *
620 * @return XMPP_EOK (0) on success or a number less than zero on failure
621 *
622 * @ingroup Stanza
623 */
624 int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
625 const char * const text)
626 {
627 if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
628
629 stanza->type = XMPP_STANZA_TEXT;
630
631 if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
632 stanza->data = xmpp_strdup(stanza->ctx, text);
633
634 return XMPP_EOK;
635 }
636
637 /** Set the text data for a text stanza.
638 * This function copies the text given and sets teh stanza object's text to
639 * it. Attempting to use this function on a stanza that has a name will
640 * fail with XMPP_EINVOP. This function takes the text as buffer and a length
641 * as opposed to a null-terminated string.
642 *
643 * @param stanza a Strophe stanza object
644 * @param text a buffer with the text
645 * @param size the length of the text
646 *
647 * @return XMPP_EOK (0) on success and a number less than 0 on failure
648 *
649 * @ingroup Stanza
650 */
651 int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
652 const char * const text,
653 const size_t size)
654 {
655 if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
656
657 stanza->type = XMPP_STANZA_TEXT;
658
659 if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
660 stanza->data = xmpp_alloc(stanza->ctx, size + 1);
661 if (!stanza->data) return XMPP_EMEM;
662
663 memcpy(stanza->data, text, size);
664 stanza->data[size] = 0;
665
666 return XMPP_EOK;
667 }
668
669 /** Get the 'id' attribute of the stanza object.
670 * This is a convenience function equivalent to:
671 * xmpp_stanza_get_attribute(stanza, "id");
672 *
673 * @param stanza a Strophe stanza object
674 *
675 * @return a string with the 'id' attribute value
676 *
677 * @ingroup Stanza
678 */
679 char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza)
680 {
681 if (stanza->type != XMPP_STANZA_TAG)
682 return NULL;
683
684 if (!stanza->attributes)
685 return NULL;
686
687 return (char *)hash_get(stanza->attributes, "id");
688 }
689
690 /** Get the namespace attribute of the stanza object.
691 * This is a convenience function equivalent to:
692 * xmpp_stanza_get_attribute(stanza, "xmlns");
693 *
694 * @param stanza a Strophe stanza object
695 *
696 * @return a string with the 'xmlns' attribute value
697 *
698 * @ingroup Stanza
699 */
700 char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza)
701 {
702 if (stanza->type != XMPP_STANZA_TAG)
703 return NULL;
704
705 if (!stanza->attributes)
706 return NULL;
707
708 return (char *)hash_get(stanza->attributes, "xmlns");
709 }
710
711 /** Get the 'type' attribute of the stanza object.
712 * This is a convenience function equivalent to:
713 * xmpp_stanza_get_attribute(stanza, "type");
714 *
715 * @param stanza a Strophe stanza object
716 *
717 * @return a string with the 'type' attribute value
718 *
719 * @ingroup Stanza
720 */
721 char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza)
722 {
723 if (stanza->type != XMPP_STANZA_TAG)
724 return NULL;
725
726 if (!stanza->attributes)
727 return NULL;
728
729 return (char *)hash_get(stanza->attributes, "type");
730 }
731
732 /** Get the first child of stanza with name.
733 * This function searches all the immediate children of stanza for a child
734 * stanza that matches the name. The first matching child is returned.
735 *
736 * @param stanza a Strophe stanza object
737 * @param name a string with the name to match
738 *
739 * @return the matching child stanza object or NULL if no match was found
740 *
741 * @ingroup Stanza
742 */
743 xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
744 const char * const name)
745 {
746 xmpp_stanza_t *child;
747
748 for (child = stanza->children; child; child = child->next) {
749 if (child->type == XMPP_STANZA_TAG &&
750 (strcmp(name, xmpp_stanza_get_name(child)) == 0))
751 break;
752 }
753
754 return child;
755 }
756
757 /** Get the first child of a stanza with a given namespace.
758 * This function searches all the immediate children of a stanza for a child
759 * stanza that matches the namespace provided. The first matching child
760 * is returned.
761 *
762 * @param stanza a Strophe stanza object
763 * @param ns a string with the namespace to match
764 *
765 * @return the matching child stanza object or NULL if no match was found
766 *
767 * @ingroup Stanza
768 */
769 xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
770 const char * const ns)
771 {
772 xmpp_stanza_t *child;
773
774 for (child = stanza->children; child; child = child->next) {
775 if (xmpp_stanza_get_ns(child) &&
776 strcmp(ns, xmpp_stanza_get_ns(child)) == 0)
777 break;
778 }
779
780 return child;
781 }
782
783 /** Get the list of children.
784 * This function returns the first child of the stanza object. The rest
785 * of the children can be obtained by calling xmpp_stanza_get_next() to
786 * iterate over the siblings.
787 *
788 * @param stanza a Strophe stanza object
789 *
790 * @return the first child stanza or NULL if there are no children
791 *
792 * @ingroup Stanza
793 */
794 xmpp_stanza_t *xmpp_stanza_get_children(xmpp_stanza_t * const stanza)
795 {
796 return stanza->children;
797 }
798
799 /** Get the next sibling of a stanza.
800 *
801 * @param stanza a Strophe stanza object
802 *
803 * @return the next sibling stanza or NULL if there are no more siblings
804 *
805 * @ingroup Stanza
806 */
807 xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t * const stanza)
808 {
809 return stanza->next;
810 }
811
812 /** Get the text data for a text stanza.
813 * This function copies the text data from a stanza and returns the new
814 * allocated string. The caller is responsible for freeing this string
815 * with xmpp_free().
816 *
817 * @param stanza a Strophe stanza object
818 *
819 * @return an allocated string with the text data
820 *
821 * @ingroup Stanza
822 */
823 char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
824 {
825 size_t len, clen;
826 xmpp_stanza_t *child;
827 char *text;
828
829 if (stanza->type == XMPP_STANZA_TEXT) {
830 if (stanza->data)
831 return xmpp_strdup(stanza->ctx, stanza->data);
832 else
833 return NULL;
834 }
835
836 len = 0;
837 for (child = stanza->children; child; child = child->next)
838 if (child->type == XMPP_STANZA_TEXT)
839 len += strlen(child->data);
840
841 if (len == 0) return NULL;
842
843 text = (char *)xmpp_alloc(stanza->ctx, len + 1);
844 if (!text) return NULL;
845
846 len = 0;
847 for (child = stanza->children; child; child = child->next)
848 if (child->type == XMPP_STANZA_TEXT) {
849 clen = strlen(child->data);
850 memcpy(&text[len], child->data, clen);
851 len += clen;
852 }
853
854 text[len] = 0;
855
856 return text;
857 }
858
859 /** Get the text data pointer for a text stanza.
860 * This function copies returns the raw pointer to the text data in the
861 * stanza. This should only be used in very special cases where the
862 * caller needs to translate the datatype as this will save a double
863 * allocation. The caller should not hold onto this pointer, and is
864 * responsible for allocating a copy if it needs one.
865 *
866 * @param stanza a Strophe stanza object
867 *
868 * @return an string pointer to the data or NULL
869 *
870 * @ingroup Stanza
871 */
872 char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza)
873 {
874 if (stanza->type == XMPP_STANZA_TEXT)
875 return stanza->data;
876 return NULL;
877 }
878
879 /** Set the 'id' attribute of a stanza.
880 *
881 * This is a convenience function for:
882 * xmpp_stanza_set_attribute(stanza, 'id', id);
883 *
884 * @param stanza a Strophe stanza object
885 * @param id a string containing the 'id' value
886 *
887 * @return XMPP_EOK (0) on success or a number less than 0 on failure
888 *
889 * @ingroup Stanza
890 */
891 int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
892 const char * const id)
893 {
894 return xmpp_stanza_set_attribute(stanza, "id", id);
895 }
896
897 /** Set the 'type' attribute of a stanza.
898 * This is a convenience function for:
899 * xmpp_stanza_set_attribute(stanza, 'type', type);
900 *
901 * @param stanza a Strophe stanza object
902 * @param type a string containing the 'type' 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_type(xmpp_stanza_t * const stanza,
909 const char * const type)
910 {
911 return xmpp_stanza_set_attribute(stanza, "type", type);
912 }
913
914 /** Get an attribute from a stanza.
915 * This function returns a pointer to the attribute value. If the caller
916 * wishes to save this value it must make its own copy.
917 *
918 * @param stanza a Strophe stanza object
919 * @param name a string containing attribute name
920 *
921 * @return a string with the attribute value or NULL on an error
922 *
923 * @ingroup Stanza
924 */
925 char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
926 const char * const name)
927 {
928 if (stanza->type != XMPP_STANZA_TAG)
929 return NULL;
930
931 if (!stanza->attributes)
932 return NULL;
933
934 return hash_get(stanza->attributes, name);
935 }