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/.autotest +9 -0
- data/History.txt +4 -0
- data/Manifest.txt +39 -0
- data/PostInstall.txt +4 -0
- data/README.rdoc +143 -0
- data/Rakefile +21 -0
- data/ext/auth.c +990 -0
- data/ext/common.h +287 -0
- data/ext/conn.c +609 -0
- data/ext/ctx.c +416 -0
- data/ext/event.c +345 -0
- data/ext/extconf.rb +6 -0
- data/ext/handler.c +592 -0
- data/ext/hash.c +278 -0
- data/ext/hash.h +64 -0
- data/ext/jid.c +177 -0
- data/ext/md5.c +289 -0
- data/ext/md5.h +41 -0
- data/ext/ostypes.h +27 -0
- data/ext/parser.c +206 -0
- data/ext/sasl.c +614 -0
- data/ext/sasl.h +44 -0
- data/ext/sha1.c +389 -0
- data/ext/sha1.h +31 -0
- data/ext/snprintf.c +839 -0
- data/ext/sock.c +911 -0
- data/ext/sock.h +51 -0
- data/ext/stanza.c +908 -0
- data/ext/strophe.h +372 -0
- data/ext/strophe_ruby.c +687 -0
- data/ext/thread.c +119 -0
- data/ext/thread.h +43 -0
- data/ext/tls.h +46 -0
- data/ext/tls_dummy.c +89 -0
- data/ext/util.c +107 -0
- data/ext/util.h +32 -0
- data/lib/strophe_ruby.rb +6 -0
- data/test/test_helper.rb +3 -0
- data/test/test_strophe_ruby.rb +11 -0
- data/test/test_strophe_ruby_extn.rb +9 -0
- metadata +108 -0
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
|
+
}
|