yong-stropheruby 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }