Merge remote-tracking branch 'cwtitan/namespace'
This commit is contained in:
@@ -866,11 +866,11 @@ void auth_handle_open(xmpp_conn_t * const conn)
|
|||||||
|
|
||||||
/* setup handler for stream:error */
|
/* setup handler for stream:error */
|
||||||
handler_add(conn, _handle_error,
|
handler_add(conn, _handle_error,
|
||||||
NULL, "stream:error", NULL, NULL);
|
XMPP_NS_STREAMS, "error", NULL, NULL);
|
||||||
|
|
||||||
/* setup handlers for incoming <stream:features> */
|
/* setup handlers for incoming <stream:features> */
|
||||||
handler_add(conn, _handle_features,
|
handler_add(conn, _handle_features,
|
||||||
NULL, "stream:features", NULL, NULL);
|
XMPP_NS_STREAMS, "features", NULL, NULL);
|
||||||
handler_add_timed(conn, _handle_missing_features,
|
handler_add_timed(conn, _handle_missing_features,
|
||||||
FEATURES_TIMEOUT, NULL);
|
FEATURES_TIMEOUT, NULL);
|
||||||
}
|
}
|
||||||
@@ -882,7 +882,7 @@ static void _handle_open_sasl(xmpp_conn_t * const conn)
|
|||||||
|
|
||||||
/* setup stream:features handlers */
|
/* setup stream:features handlers */
|
||||||
handler_add(conn, _handle_features_sasl,
|
handler_add(conn, _handle_features_sasl,
|
||||||
NULL, "stream:features", NULL, NULL);
|
XMPP_NS_STREAMS, "features", NULL, NULL);
|
||||||
handler_add_timed(conn, _handle_missing_features_sasl,
|
handler_add_timed(conn, _handle_missing_features_sasl,
|
||||||
FEATURES_TIMEOUT, NULL);
|
FEATURES_TIMEOUT, NULL);
|
||||||
}
|
}
|
||||||
@@ -1168,7 +1168,7 @@ void auth_handle_component_open(xmpp_conn_t * const conn)
|
|||||||
/* reset all timed handlers */
|
/* reset all timed handlers */
|
||||||
handler_reset_timed(conn, 0);
|
handler_reset_timed(conn, 0);
|
||||||
|
|
||||||
handler_add(conn, _handle_error, NULL, "stream:error", NULL, NULL);
|
handler_add(conn, _handle_error, XMPP_NS_STREAMS, "error", NULL, NULL);
|
||||||
handler_add(conn, _handle_component_hs_response, NULL,
|
handler_add(conn, _handle_component_hs_response, NULL,
|
||||||
"handshake", NULL, NULL);
|
"handshake", NULL, NULL);
|
||||||
handler_add_timed(conn, _handle_missing_handshake, HANDSHAKE_TIMEOUT, NULL);
|
handler_add_timed(conn, _handle_missing_handshake, HANDSHAKE_TIMEOUT, NULL);
|
||||||
|
|||||||
@@ -789,7 +789,7 @@ static void _handle_stream_start(char *name, char **attrs,
|
|||||||
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
||||||
char *id;
|
char *id;
|
||||||
|
|
||||||
if (strcmp(name, "stream:stream") != 0) {
|
if (strcmp(name, "stream")) {
|
||||||
printf("name = %s\n", name);
|
printf("name = %s\n", name);
|
||||||
xmpp_error(conn->ctx, "conn", "Server did not open valid stream.");
|
xmpp_error(conn->ctx, "conn", "Server did not open valid stream.");
|
||||||
conn_disconnect(conn);
|
conn_disconnect(conn);
|
||||||
|
|||||||
@@ -23,6 +23,9 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
|
/* ASCII FF is invalid UTF-8 and should never be present in well-formed XML */
|
||||||
|
#define NAMESPACE_SEP ('\xFF')
|
||||||
|
|
||||||
struct _parser_t {
|
struct _parser_t {
|
||||||
xmpp_ctx_t *ctx;
|
xmpp_ctx_t *ctx;
|
||||||
XML_Parser expat;
|
XML_Parser expat;
|
||||||
@@ -34,23 +37,71 @@ struct _parser_t {
|
|||||||
xmpp_stanza_t *stanza;
|
xmpp_stanza_t *stanza;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* return allocated string with the name from a delimited
|
||||||
|
* namespace/name string */
|
||||||
|
static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
|
||||||
|
{
|
||||||
|
char *result = NULL;
|
||||||
|
const char *c;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
c = strchr(nsname, NAMESPACE_SEP);
|
||||||
|
if (c == NULL) return xmpp_strdup(ctx, nsname);
|
||||||
|
|
||||||
|
c++;
|
||||||
|
len = strlen(c);
|
||||||
|
result = xmpp_alloc(ctx, len + 1);
|
||||||
|
if (result != NULL) {
|
||||||
|
memcpy(result, c, len);
|
||||||
|
result[len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return allocated string with the namespace from a delimited string */
|
||||||
|
static char *_xml_namespace(xmpp_ctx_t *ctx, const char *nsname)
|
||||||
|
{
|
||||||
|
char *result = NULL;
|
||||||
|
const char *c;
|
||||||
|
|
||||||
|
c = strchr(nsname, NAMESPACE_SEP);
|
||||||
|
if (c != NULL) {
|
||||||
|
result = xmpp_alloc(ctx, (c-nsname) + 1);
|
||||||
|
if (result != NULL) {
|
||||||
|
memcpy(result, nsname, (c-nsname));
|
||||||
|
result[c-nsname] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static void _set_attributes(xmpp_stanza_t *stanza, const XML_Char **attrs)
|
static void _set_attributes(xmpp_stanza_t *stanza, const XML_Char **attrs)
|
||||||
{
|
{
|
||||||
|
char *attr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!attrs) return;
|
if (!attrs) return;
|
||||||
|
|
||||||
for (i = 0; attrs[i]; i += 2) {
|
for (i = 0; attrs[i]; i += 2) {
|
||||||
xmpp_stanza_set_attribute(stanza, attrs[i], attrs[i+1]);
|
/* namespaced attributes aren't used in xmpp, discard namespace */
|
||||||
|
attr = _xml_name(stanza->ctx, attrs[i]);
|
||||||
|
xmpp_stanza_set_attribute(stanza, attr, attrs[i+1]);
|
||||||
|
xmpp_free(stanza->ctx, attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _start_element(void *userdata,
|
static void _start_element(void *userdata,
|
||||||
const XML_Char *name,
|
const XML_Char *nsname,
|
||||||
const XML_Char **attrs)
|
const XML_Char **attrs)
|
||||||
{
|
{
|
||||||
parser_t *parser = (parser_t *)userdata;
|
parser_t *parser = (parser_t *)userdata;
|
||||||
xmpp_stanza_t *child;
|
xmpp_stanza_t *child;
|
||||||
|
char *ns, *name;
|
||||||
|
|
||||||
|
ns = _xml_namespace(parser->ctx, nsname);
|
||||||
|
name = _xml_name(parser->ctx, nsname);
|
||||||
|
|
||||||
if (parser->depth == 0) {
|
if (parser->depth == 0) {
|
||||||
/* notify the owner */
|
/* notify the owner */
|
||||||
@@ -71,6 +122,8 @@ static void _start_element(void *userdata,
|
|||||||
}
|
}
|
||||||
xmpp_stanza_set_name(parser->stanza, name);
|
xmpp_stanza_set_name(parser->stanza, name);
|
||||||
_set_attributes(parser->stanza, attrs);
|
_set_attributes(parser->stanza, attrs);
|
||||||
|
if (ns)
|
||||||
|
xmpp_stanza_set_ns(parser->stanza, ns);
|
||||||
} else {
|
} else {
|
||||||
/* starting a child of parser->stanza */
|
/* starting a child of parser->stanza */
|
||||||
child = xmpp_stanza_new(parser->ctx);
|
child = xmpp_stanza_new(parser->ctx);
|
||||||
@@ -79,6 +132,8 @@ static void _start_element(void *userdata,
|
|||||||
}
|
}
|
||||||
xmpp_stanza_set_name(child, name);
|
xmpp_stanza_set_name(child, name);
|
||||||
_set_attributes(child, attrs);
|
_set_attributes(child, attrs);
|
||||||
|
if (ns)
|
||||||
|
xmpp_stanza_set_ns(child, ns);
|
||||||
|
|
||||||
/* add child to parent */
|
/* add child to parent */
|
||||||
xmpp_stanza_add_child(parser->stanza, child);
|
xmpp_stanza_add_child(parser->stanza, child);
|
||||||
@@ -91,6 +146,9 @@ static void _start_element(void *userdata,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ns) xmpp_free(parser->ctx, ns);
|
||||||
|
if (name) xmpp_free(parser->ctx, name);
|
||||||
|
|
||||||
parser->depth++;
|
parser->depth++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +238,7 @@ int parser_reset(parser_t *parser)
|
|||||||
if (parser->stanza)
|
if (parser->stanza)
|
||||||
xmpp_stanza_release(parser->stanza);
|
xmpp_stanza_release(parser->stanza);
|
||||||
|
|
||||||
parser->expat = XML_ParserCreate(NULL);
|
parser->expat = XML_ParserCreateNS(NULL, NAMESPACE_SEP);
|
||||||
if (!parser->expat) return 0;
|
if (!parser->expat) return 0;
|
||||||
|
|
||||||
parser->depth = 0;
|
parser->depth = 0;
|
||||||
|
|||||||
@@ -36,28 +36,91 @@ struct _parser_t {
|
|||||||
xmpp_stanza_t *stanza;
|
xmpp_stanza_t *stanza;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void _set_attributes(xmpp_stanza_t *stanza, const xmlChar **attrs)
|
static void _set_attributes(xmpp_stanza_t *stanza, int nattrs,
|
||||||
|
const xmlChar **attrs)
|
||||||
{
|
{
|
||||||
int i;
|
int i, len;
|
||||||
|
char *value;
|
||||||
|
|
||||||
if (!attrs) return;
|
if (!attrs) return;
|
||||||
|
|
||||||
for (i = 0; attrs[i]; i += 2) {
|
/* SAX2 uses array of localname/prefix/uri/value_begin/value_end */
|
||||||
xmpp_stanza_set_attribute(stanza, (const char *)attrs[i], (const char *)attrs[i+1]);
|
for (i = 0; i < nattrs*5; i += 5) {
|
||||||
|
len = attrs[i+4] - attrs[i+3];
|
||||||
|
value = xmpp_alloc(stanza->ctx, len + 1);
|
||||||
|
if (value) {
|
||||||
|
memcpy(value, attrs[i+3], len);
|
||||||
|
value[len] = '\0';
|
||||||
|
xmpp_stanza_set_attribute(stanza, (const char *)attrs[i], value);
|
||||||
|
xmpp_free(stanza->ctx, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SAX2 gives us the attrs in an incredibly inconvenient array,
|
||||||
|
* convert it to what the start callback is expecting */
|
||||||
|
static char **_convert_attrs(parser_t *parser, int nattrs,
|
||||||
|
const xmlChar **attrs)
|
||||||
|
{
|
||||||
|
int c, i, o, len;
|
||||||
|
char *value;
|
||||||
|
char **ret;
|
||||||
|
|
||||||
|
if (!attrs) return NULL;
|
||||||
|
|
||||||
|
ret = xmpp_alloc(parser->ctx, (nattrs+1)*2*sizeof(char*));
|
||||||
|
if (!ret) return NULL;
|
||||||
|
memset(ret, 0, (nattrs+1)*2*sizeof(char*));
|
||||||
|
|
||||||
|
for (c = 0; c < nattrs; c++) {
|
||||||
|
i = c * 5;
|
||||||
|
o = c * 2;
|
||||||
|
|
||||||
|
len = attrs[i+4] - attrs[i+3];
|
||||||
|
value = xmpp_alloc(parser->ctx, len + 1);
|
||||||
|
if (value) {
|
||||||
|
memcpy(value, attrs[i+3], len);
|
||||||
|
value[len] = '\0';
|
||||||
|
ret[o] = xmpp_strdup(parser->ctx, (char*)attrs[i]);
|
||||||
|
ret[o+1] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _free_cbattrs(parser_t *parser, char **attrs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!attrs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; attrs[i]; i += 2) {
|
||||||
|
if (attrs[i]) xmpp_free(parser->ctx, attrs[i]);
|
||||||
|
if (attrs[i+1]) xmpp_free(parser->ctx, attrs[i+1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
xmpp_free(parser->ctx, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
static void _start_element(void *userdata,
|
static void _start_element(void *userdata,
|
||||||
const xmlChar *name, const xmlChar **attrs)
|
const xmlChar *name, const xmlChar *prefix,
|
||||||
|
const xmlChar *uri, int nnamespaces,
|
||||||
|
const xmlChar **namespaces, int nattrs,
|
||||||
|
int ndefaulted, const xmlChar **attrs)
|
||||||
{
|
{
|
||||||
parser_t *parser = (parser_t *)userdata;
|
parser_t *parser = (parser_t *)userdata;
|
||||||
xmpp_stanza_t *child;
|
xmpp_stanza_t *child;
|
||||||
|
char **cbattrs;
|
||||||
|
|
||||||
if (parser->depth == 0) {
|
if (parser->depth == 0) {
|
||||||
/* notify the owner */
|
/* notify the owner */
|
||||||
if (parser->startcb)
|
if (parser->startcb)
|
||||||
parser->startcb((char *)name, (char **)attrs,
|
cbattrs = _convert_attrs(parser, nattrs, attrs);
|
||||||
|
parser->startcb((char *)name, cbattrs,
|
||||||
parser->userdata);
|
parser->userdata);
|
||||||
|
_free_cbattrs(parser, cbattrs);
|
||||||
} else {
|
} else {
|
||||||
/* build stanzas at depth 1 */
|
/* build stanzas at depth 1 */
|
||||||
if (!parser->stanza && parser->depth != 1) {
|
if (!parser->stanza && parser->depth != 1) {
|
||||||
@@ -71,7 +134,9 @@ static void _start_element(void *userdata,
|
|||||||
/* FIXME: can't allocate, disconnect */
|
/* FIXME: can't allocate, disconnect */
|
||||||
}
|
}
|
||||||
xmpp_stanza_set_name(parser->stanza, (char *)name);
|
xmpp_stanza_set_name(parser->stanza, (char *)name);
|
||||||
_set_attributes(parser->stanza, attrs);
|
_set_attributes(parser->stanza, nattrs, attrs);
|
||||||
|
if (uri)
|
||||||
|
xmpp_stanza_set_ns(parser->stanza, (char *)uri);
|
||||||
} else {
|
} else {
|
||||||
/* starting a child of conn->stanza */
|
/* starting a child of conn->stanza */
|
||||||
child = xmpp_stanza_new(parser->ctx);
|
child = xmpp_stanza_new(parser->ctx);
|
||||||
@@ -79,7 +144,9 @@ static void _start_element(void *userdata,
|
|||||||
/* FIXME: can't allocate, disconnect */
|
/* FIXME: can't allocate, disconnect */
|
||||||
}
|
}
|
||||||
xmpp_stanza_set_name(child, (char *)name);
|
xmpp_stanza_set_name(child, (char *)name);
|
||||||
_set_attributes(child, attrs);
|
_set_attributes(child, nattrs, attrs);
|
||||||
|
if (uri)
|
||||||
|
xmpp_stanza_set_ns(child, (char *)uri);
|
||||||
|
|
||||||
/* add child to parent */
|
/* add child to parent */
|
||||||
xmpp_stanza_add_child(parser->stanza, child);
|
xmpp_stanza_add_child(parser->stanza, child);
|
||||||
@@ -95,7 +162,8 @@ static void _start_element(void *userdata,
|
|||||||
parser->depth++;
|
parser->depth++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _end_element(void *userdata, const xmlChar *name)
|
static void _end_element(void *userdata, const xmlChar *name,
|
||||||
|
const xmlChar *prefix, const xmlChar *uri)
|
||||||
{
|
{
|
||||||
parser_t *parser = (parser_t *)userdata;
|
parser_t *parser = (parser_t *)userdata;
|
||||||
|
|
||||||
@@ -153,8 +221,9 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
|
|||||||
parser->ctx = ctx;
|
parser->ctx = ctx;
|
||||||
parser->xmlctx = NULL;
|
parser->xmlctx = NULL;
|
||||||
memset(&parser->handlers, 0, sizeof(xmlSAXHandler));
|
memset(&parser->handlers, 0, sizeof(xmlSAXHandler));
|
||||||
parser->handlers.startElement = _start_element;
|
parser->handlers.initialized = XML_SAX2_MAGIC;
|
||||||
parser->handlers.endElement = _end_element;
|
parser->handlers.startElementNs = _start_element;
|
||||||
|
parser->handlers.endElementNs = _end_element;
|
||||||
parser->handlers.characters = _characters;
|
parser->handlers.characters = _characters;
|
||||||
parser->startcb = startcb;
|
parser->startcb = startcb;
|
||||||
parser->endcb = endcb;
|
parser->endcb = endcb;
|
||||||
|
|||||||
14
src/stanza.c
14
src/stanza.c
@@ -317,6 +317,20 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
|||||||
if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) {
|
if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) {
|
||||||
iter = hash_iter_new(stanza->attributes);
|
iter = hash_iter_new(stanza->attributes);
|
||||||
while ((key = hash_iter_next(iter))) {
|
while ((key = hash_iter_next(iter))) {
|
||||||
|
if (!strcmp(key, "xmlns")) {
|
||||||
|
/* don't output namespace if parent stanza is the same */
|
||||||
|
if (stanza->parent &&
|
||||||
|
stanza->parent->attributes &&
|
||||||
|
hash_get(stanza->parent->attributes, key) &&
|
||||||
|
!strcmp((char*)hash_get(stanza->attributes, key),
|
||||||
|
(char*)hash_get(stanza->parent->attributes, key)))
|
||||||
|
continue;
|
||||||
|
/* or if this is the stream namespace */
|
||||||
|
if (!stanza->parent &&
|
||||||
|
!strcmp((char*)hash_get(stanza->attributes, key),
|
||||||
|
XMPP_NS_CLIENT))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
tmp = _escape_xml(stanza->ctx,
|
tmp = _escape_xml(stanza->ctx,
|
||||||
(char *)hash_get(stanza->attributes, key));
|
(char *)hash_get(stanza->attributes, key));
|
||||||
if (tmp == NULL) return XMPP_EMEM;
|
if (tmp == NULL) return XMPP_EMEM;
|
||||||
|
|||||||
@@ -34,14 +34,14 @@ END_TEST
|
|||||||
int cbtest_got_start = 0;
|
int cbtest_got_start = 0;
|
||||||
void cbtest_handle_start(char *name, char **attrs, void *userdata)
|
void cbtest_handle_start(char *name, char **attrs, void *userdata)
|
||||||
{
|
{
|
||||||
if (strcmp(name, "stream:stream") == 0)
|
if (strcmp(name, "stream") == 0)
|
||||||
cbtest_got_start = 1;
|
cbtest_got_start = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cbtest_got_end = 0;
|
int cbtest_got_end = 0;
|
||||||
void cbtest_handle_end(char *name, void *userdata)
|
void cbtest_handle_end(char *name, void *userdata)
|
||||||
{
|
{
|
||||||
if (strcmp(name, "stream:stream") == 0)
|
if (strcmp(name, "stream") == 0)
|
||||||
cbtest_got_end = 1;
|
cbtest_got_end = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,9 +64,9 @@ START_TEST(callbacks)
|
|||||||
cbtest_handle_end,
|
cbtest_handle_end,
|
||||||
cbtest_handle_stanza, NULL);
|
cbtest_handle_stanza, NULL);
|
||||||
|
|
||||||
ret = parser_feed(parser, "<stream:stream>", 15);
|
ret = parser_feed(parser, "<stream>", 8);
|
||||||
ret = parser_feed(parser, "<message/>", 10);
|
ret = parser_feed(parser, "<message/>", 10);
|
||||||
parser_feed(parser, "</stream:stream>", 16);
|
parser_feed(parser, "</stream>", 9);
|
||||||
|
|
||||||
fail_unless(cbtest_got_start == 1);
|
fail_unless(cbtest_got_start == 1);
|
||||||
fail_unless(cbtest_got_end == 1);
|
fail_unless(cbtest_got_end == 1);
|
||||||
|
|||||||
Reference in New Issue
Block a user