stropheruby 0.1.3

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