summaryrefslogtreecommitdiff
path: root/src/rexmpp.c
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2023-05-23 12:05:13 +0300
committerdefanor <defanor@uberspace.net>2023-05-23 12:05:13 +0300
commit122b13ec955deb718aca280112584b645c9caea0 (patch)
treefdaa1dce84956a33f669605e67df1a587a01fc1d /src/rexmpp.c
parentae42bb94fd49a450690014b6039a812a251f64cd (diff)
Replace libxml2's xmlNode with a custom XML structure
The new structure (rexmpp_xml) is simpler, and should allow manipulation from Rust without any dependency on libxml2 from the Rust code (while Rust has its own parsers, such as rxml). Alternative XML parsers (e.g., libexpat) now can be used from the C code. The replacement/abstraction is not quite complete yet: the parsing process itself (xmlParseChunk and friends) should be abstracted out.
Diffstat (limited to 'src/rexmpp.c')
-rw-r--r--src/rexmpp.c790
1 files changed, 316 insertions, 474 deletions
diff --git a/src/rexmpp.c b/src/rexmpp.c
index c29574e..80d7cc2 100644
--- a/src/rexmpp.c
+++ b/src/rexmpp.c
@@ -29,6 +29,7 @@
#endif
#include "rexmpp.h"
+#include "rexmpp_xml.h"
#include "rexmpp_tcp.h"
#include "rexmpp_socks.h"
#include "rexmpp_roster.h"
@@ -114,21 +115,21 @@ void rexmpp_log (rexmpp_t *s, int priority, const char *format, ...)
}
}
-char *rexmpp_capabilities_string (rexmpp_t *s, xmlNodePtr info) {
+char *rexmpp_capabilities_string (rexmpp_t *s, rexmpp_xml_t *info) {
/* Assuming the info is sorted already. Would be better to sort it
here (todo). */
- xmlNodePtr cur;
+ rexmpp_xml_t *cur;
int buf_len = 1024, str_len = 0;
char *str = malloc(buf_len);
for (cur = info; cur; cur = cur->next) {
- if (strcmp(cur->name, "identity") == 0) {
+ if (strcmp(cur->alt.elem.qname.name, "identity") == 0) {
int cur_len = 5; /* ///< for an empty identity */
/* Collect the properties we'll need. */
- char *category = xmlGetProp(cur, "category");
- char *type = xmlGetProp(cur, "type");
- char *lang = xmlGetProp(cur, "xml:lang");
- char *name = xmlGetProp(cur, "name");
+ const char *category = rexmpp_xml_find_attr_val(cur, "category");
+ const char *type = rexmpp_xml_find_attr_val(cur, "type");
+ const char *lang = rexmpp_xml_find_attr_val(cur, "xml:lang");
+ const char *name = rexmpp_xml_find_attr_val(cur, "name");
/* Calculate the length needed. */
if (category != NULL) {
@@ -177,22 +178,8 @@ char *rexmpp_capabilities_string (rexmpp_t *s, xmlNodePtr info) {
}
str[str_len] = '<';
str_len++;
-
- /* Free the values. */
- if (category != NULL) {
- free(category);
- }
- if (type != NULL) {
- free(type);
- }
- if (lang != NULL) {
- free(lang);
- }
- if (name != NULL) {
- free(name);
- }
- } else if (strcmp(cur->name, "feature") == 0) {
- char *var = xmlGetProp(cur, "var");
+ } else if (strcmp(cur->alt.elem.qname.name, "feature") == 0) {
+ const char *var = rexmpp_xml_find_attr_val(cur, "var");
int cur_len = 2 + strlen(var);
if (cur_len > buf_len - str_len) {
while (cur_len > buf_len - str_len) {
@@ -204,10 +191,9 @@ char *rexmpp_capabilities_string (rexmpp_t *s, xmlNodePtr info) {
str_len += strlen(var);
str[str_len] = '<';
str_len++;
- free(var);
} else {
rexmpp_log(s, LOG_ERR,
- "Unsupported node type in disco info: %s", cur->name);
+ "Unsupported node type in disco info: %s", cur->alt.elem.qname.name);
}
}
str[str_len] = '\0';
@@ -215,7 +201,7 @@ char *rexmpp_capabilities_string (rexmpp_t *s, xmlNodePtr info) {
}
char *rexmpp_capabilities_hash (rexmpp_t *s,
- xmlNodePtr info)
+ rexmpp_xml_t *info)
{
char *out = NULL;
size_t out_len = 0;
@@ -233,38 +219,35 @@ char *rexmpp_capabilities_hash (rexmpp_t *s,
return out;
}
-xmlNodePtr rexmpp_find_event (rexmpp_t *s,
- const char *from,
- const char *node,
- xmlNodePtr *prev_event)
+rexmpp_xml_t *rexmpp_find_event (rexmpp_t *s,
+ const char *from,
+ const char *node,
+ rexmpp_xml_t **prev_event)
{
- xmlNodePtr prev, cur;
+ rexmpp_xml_t *prev, *cur;
for (prev = NULL, cur = s->roster_events;
cur != NULL;
- prev = cur, cur = xmlNextElementSibling(cur)) {
- char *cur_from = xmlGetProp(cur, "from");
+ prev = cur, cur = cur->next) {
+ const char *cur_from = rexmpp_xml_find_attr_val(cur, "from");
if (cur_from == NULL) {
continue;
}
- xmlNodePtr cur_event =
+ rexmpp_xml_t *cur_event =
rexmpp_xml_find_child(cur,
"http://jabber.org/protocol/pubsub#event",
"event");
- xmlNodePtr cur_items =
+ rexmpp_xml_t *cur_items =
rexmpp_xml_find_child(cur_event,
"http://jabber.org/protocol/pubsub#event",
"items");
if (cur_items == NULL) {
- free(cur_from);
continue;
}
- char *cur_node = xmlGetProp(cur_items, "node");
+ const char *cur_node = rexmpp_xml_find_attr_val(cur_items, "node");
if (cur_node == NULL) {
continue;
}
int match = (strcmp(cur_from, from) == 0 && strcmp(cur_node, node) == 0);
- free(cur_node);
- free(cur_from);
if (match) {
if (prev_event != NULL) {
*prev_event = prev;
@@ -282,36 +265,39 @@ char *rexmpp_get_name (rexmpp_t *s, const char *jid_str) {
return NULL;
}
if (s->manage_roster) {
- xmlNodePtr roster_item = rexmpp_roster_find_item(s, jid.bare, NULL);
- if (roster_item) {
- char *name = xmlGetProp(roster_item, "name");
+ rexmpp_xml_t *roster_item = rexmpp_roster_find_item(s, jid.bare, NULL);
+ if (roster_item != NULL) {
+ char *name = strdup(rexmpp_xml_find_attr_val(roster_item, "name"));
if (name != NULL) {
return name;
}
}
if (s->track_roster_events) {
- xmlNodePtr elem =
+ rexmpp_xml_t *elem =
rexmpp_find_event(s, jid.bare, "http://jabber.org/protocol/nick", NULL);
if (elem != NULL) {
- xmlNodePtr event =
+ rexmpp_xml_t *event =
rexmpp_xml_find_child(elem,
"http://jabber.org/protocol/pubsub#event",
"event");
- xmlNodePtr items =
+ rexmpp_xml_t *items =
rexmpp_xml_find_child(event,
"http://jabber.org/protocol/pubsub#event",
"items");
- xmlNodePtr item =
+ rexmpp_xml_t *item =
rexmpp_xml_find_child(items,
"http://jabber.org/protocol/pubsub#event",
"item");
if (item != NULL) {
- xmlNodePtr nick =
+ rexmpp_xml_t *nick =
rexmpp_xml_find_child(item,
"http://jabber.org/protocol/nick",
"nick");
- if (nick != NULL) {
- return xmlNodeGetContent(nick);
+ if (nick != NULL &&
+ nick->type == REXMPP_XML_ELEMENT &&
+ nick->alt.elem.children != NULL &&
+ nick->alt.elem.children->type == REXMPP_XML_TEXT) {
+ return strdup(rexmpp_xml_text_child(nick));
}
}
}
@@ -323,93 +309,75 @@ char *rexmpp_get_name (rexmpp_t *s, const char *jid_str) {
return strdup(jid.bare);
}
-xmlNodePtr rexmpp_xml_feature (const char *var) {
- xmlNodePtr feature = xmlNewNode(NULL, "feature");
- xmlNewProp(feature, "var", var);
+rexmpp_xml_t *rexmpp_xml_feature (const char *var) {
+ rexmpp_xml_t *feature = rexmpp_xml_new_elem("feature", NULL);
+ rexmpp_xml_add_attr(feature, "var", var);
return feature;
}
-xmlNodePtr rexmpp_xml_new_node (const char *name, const char *namespace) {
- xmlNodePtr node = xmlNewNode(NULL, name);
- xmlNewNs(node, namespace, NULL);
- return node;
-}
-
-xmlNodePtr rexmpp_xml_error (const char *type, const char *condition) {
- xmlNodePtr error = xmlNewNode(NULL, "error");
- xmlNewProp(error, "type", type);
- xmlNodePtr cond = xmlNewNode(NULL, condition);
- xmlNewNs(cond, "urn:ietf:params:xml:ns:xmpp-stanzas", NULL);
- xmlAddChild(error, cond);
- return error;
-}
-
void rexmpp_disco_find_feature_cb (rexmpp_t *s,
void *ptr,
- xmlNodePtr request,
- xmlNodePtr response,
+ rexmpp_xml_t *request,
+ rexmpp_xml_t *response,
int success)
{
struct rexmpp_feature_search *search = ptr;
if (! success) {
- char *to = xmlGetProp(request, "to");
- xmlNodePtr query = xmlFirstElementChild(request);
- rexmpp_log(s, LOG_ERR, "Failed to query %s for %s.", to, query->nsDef->href);
- free(to);
+ const char *to = rexmpp_xml_find_attr_val(request, "to");
+ rexmpp_xml_t *query = request->alt.elem.children;
+ rexmpp_log(s, LOG_ERR, "Failed to query %s for %s.", to, query->alt.elem.qname.namespace);
} else if (! search->found) {
- xmlNodePtr query = xmlFirstElementChild(response);
+ rexmpp_xml_t *query = rexmpp_xml_first_elem_child(response);
if (rexmpp_xml_match(query, "http://jabber.org/protocol/disco#info",
"query")) {
- xmlNodePtr child = xmlFirstElementChild(query);
+ rexmpp_xml_t *child = rexmpp_xml_first_elem_child(query);
while (child != NULL && (! search->found)) {
if (rexmpp_xml_match(child, "http://jabber.org/protocol/disco#info",
"feature")) {
- char *var = xmlGetProp(child, "var");
+ const char *var = rexmpp_xml_find_attr_val(child, "var");
if (var != NULL) {
if (strcmp(var, search->feature_var) == 0) {
search->cb(s, search->cb_data, request, response, success);
search->found = 1;
}
- free(var);
}
}
- child = child->next;
+ child = rexmpp_xml_next_elem_sibling(child);
}
if ((! search->found) && (search->max_requests > 0)) {
/* Still not found, request items */
- char *jid = xmlGetProp(request, "to");
+ const char *jid = rexmpp_xml_find_attr_val(request, "to");
if (jid != NULL) {
search->pending++;
search->max_requests--;
- xmlNodePtr query =
- rexmpp_xml_new_node("query",
+ rexmpp_xml_t *query =
+ rexmpp_xml_new_elem("query",
"http://jabber.org/protocol/disco#items");
rexmpp_cached_iq_new(s, "get", jid, query,
rexmpp_disco_find_feature_cb,
search, search->fresh);
- free(jid);
}
}
} else if (rexmpp_xml_match(query,
"http://jabber.org/protocol/disco#items",
"query")) {
- xmlNodePtr child = xmlFirstElementChild(query);
+ rexmpp_xml_t *child = rexmpp_xml_first_elem_child(query);
while (child != NULL && (search->max_requests > 0)) {
if (rexmpp_xml_match(child, "http://jabber.org/protocol/disco#items",
"item")) {
- char *jid = xmlGetProp(child, "jid");
+ const char *jid = rexmpp_xml_find_attr_val(child, "jid");
if (jid != NULL) {
search->pending++;
search->max_requests--;
- xmlNodePtr query =
- rexmpp_xml_new_node("query",
+ rexmpp_xml_t *query =
+ rexmpp_xml_new_elem("query",
"http://jabber.org/protocol/disco#info");
rexmpp_cached_iq_new(s, "get", jid, query,
rexmpp_disco_find_feature_cb,
search, search->fresh);
}
}
- child = child->next;
+ child = rexmpp_xml_next_elem_sibling(child);
}
}
}
@@ -440,8 +408,8 @@ rexmpp_disco_find_feature (rexmpp_t *s,
search->cb_data = cb_data;
search->fresh = fresh;
search->feature_var = feature_var;
- xmlNodePtr query =
- rexmpp_xml_new_node("query", "http://jabber.org/protocol/disco#info");
+ rexmpp_xml_t *query =
+ rexmpp_xml_new_elem("query", "http://jabber.org/protocol/disco#info");
if (jid == NULL) {
jid = s->initial_jid.domain;
}
@@ -449,18 +417,18 @@ rexmpp_disco_find_feature (rexmpp_t *s,
rexmpp_disco_find_feature_cb, search, fresh);
}
-xmlNodePtr rexmpp_disco_info (rexmpp_t *s) {
+rexmpp_xml_t *rexmpp_disco_info (rexmpp_t *s) {
if (s->disco_info != NULL) {
return s->disco_info;
}
- xmlNodePtr prev = NULL, cur;
+ rexmpp_xml_t *prev = NULL, *cur;
/* There must be at least one identity, so filling in somewhat
sensible defaults. A basic client may leave them be, while an
advanced one would adjust and/or extend them. */
- s->disco_info = xmlNewNode(NULL, "identity");
- xmlNewProp(s->disco_info, "category", "client");
- xmlNewProp(s->disco_info, "type", s->client_type);
- xmlNewProp(s->disco_info, "name", s->client_name);
+ s->disco_info = rexmpp_xml_new_elem("identity", NULL);
+ rexmpp_xml_add_attr(s->disco_info, "category", "client");
+ rexmpp_xml_add_attr(s->disco_info, "type", s->client_type);
+ rexmpp_xml_add_attr(s->disco_info, "name", s->client_name);
prev = s->disco_info;
cur = rexmpp_xml_feature("http://jabber.org/protocol/disco#info");
prev->next = cur;
@@ -601,37 +569,37 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s,
external for now, this may be adjusted by an application or a
user. */
s->jingle_rtp_description =
- rexmpp_xml_new_node("description", "urn:xmpp:jingle:apps:rtp:1");
- xmlNewProp(s->jingle_rtp_description, "media", "audio");
- xmlNodePtr pl_type;
-
- pl_type = rexmpp_xml_new_node("payload-type", "urn:xmpp:jingle:apps:rtp:1");
- xmlNewProp(pl_type, "id", "97");
- xmlNewProp(pl_type, "name", "opus");
- xmlNewProp(pl_type, "clockrate", "48000");
- xmlNewProp(pl_type, "channels", "2");
- xmlAddChild(s->jingle_rtp_description, pl_type);
-
- pl_type = rexmpp_xml_new_node("payload-type", "urn:xmpp:jingle:apps:rtp:1");
- xmlNewProp(pl_type, "id", "96");
- xmlNewProp(pl_type, "name", "speex");
- xmlNewProp(pl_type, "clockrate", "32000");
- xmlNewProp(pl_type, "channels", "1");
- xmlAddChild(s->jingle_rtp_description, pl_type);
-
- pl_type = rexmpp_xml_new_node("payload-type", "urn:xmpp:jingle:apps:rtp:1");
- xmlNewProp(pl_type, "id", "0");
- xmlNewProp(pl_type, "name", "PCMU");
- xmlNewProp(pl_type, "clockrate", "8000");
- xmlNewProp(pl_type, "channels", "1");
- xmlAddChild(s->jingle_rtp_description, pl_type);
-
- pl_type = rexmpp_xml_new_node("payload-type", "urn:xmpp:jingle:apps:rtp:1");
- xmlNewProp(pl_type, "id", "8");
- xmlNewProp(pl_type, "name", "PCMA");
- xmlNewProp(pl_type, "clockrate", "8000");
- xmlNewProp(pl_type, "channels", "1");
- xmlAddChild(s->jingle_rtp_description, pl_type);
+ rexmpp_xml_new_elem("description", "urn:xmpp:jingle:apps:rtp:1");
+ rexmpp_xml_add_attr(s->jingle_rtp_description, "media", "audio");
+ rexmpp_xml_t *pl_type;
+
+ pl_type = rexmpp_xml_new_elem("payload-type", "urn:xmpp:jingle:apps:rtp:1");
+ rexmpp_xml_add_attr(pl_type, "id", "97");
+ rexmpp_xml_add_attr(pl_type, "name", "opus");
+ rexmpp_xml_add_attr(pl_type, "clockrate", "48000");
+ rexmpp_xml_add_attr(pl_type, "channels", "2");
+ rexmpp_xml_add_child(s->jingle_rtp_description, pl_type);
+
+ pl_type = rexmpp_xml_new_elem("payload-type", "urn:xmpp:jingle:apps:rtp:1");
+ rexmpp_xml_add_attr(pl_type, "id", "96");
+ rexmpp_xml_add_attr(pl_type, "name", "speex");
+ rexmpp_xml_add_attr(pl_type, "clockrate", "32000");
+ rexmpp_xml_add_attr(pl_type, "channels", "1");
+ rexmpp_xml_add_child(s->jingle_rtp_description, pl_type);
+
+ pl_type = rexmpp_xml_new_elem("payload-type", "urn:xmpp:jingle:apps:rtp:1");
+ rexmpp_xml_add_attr(pl_type, "id", "0");
+ rexmpp_xml_add_attr(pl_type, "name", "PCMU");
+ rexmpp_xml_add_attr(pl_type, "clockrate", "8000");
+ rexmpp_xml_add_attr(pl_type, "channels", "1");
+ rexmpp_xml_add_child(s->jingle_rtp_description, pl_type);
+
+ pl_type = rexmpp_xml_new_elem("payload-type", "urn:xmpp:jingle:apps:rtp:1");
+ rexmpp_xml_add_attr(pl_type, "id", "8");
+ rexmpp_xml_add_attr(pl_type, "name", "PCMA");
+ rexmpp_xml_add_attr(pl_type, "clockrate", "8000");
+ rexmpp_xml_add_attr(pl_type, "channels", "1");
+ rexmpp_xml_add_child(s->jingle_rtp_description, pl_type);
if (jid == NULL) {
rexmpp_log(s, LOG_CRIT, "No initial JID is provided.");
@@ -744,11 +712,11 @@ void rexmpp_cleanup (rexmpp_t *s) {
s->send_buffer = NULL;
}
if (s->stream_features != NULL) {
- xmlFreeNode(s->stream_features);
+ rexmpp_xml_free(s->stream_features);
s->stream_features = NULL;
}
if (s->send_queue != NULL) {
- xmlFreeNodeList(s->send_queue);
+ rexmpp_xml_free_list(s->send_queue);
s->send_queue = NULL;
}
if (s->current_element_root != NULL) {
@@ -778,12 +746,12 @@ void rexmpp_cleanup (rexmpp_t *s) {
void rexmpp_iq_finish (rexmpp_t *s,
rexmpp_iq_t *iq,
int success,
- xmlNodePtr response)
+ rexmpp_xml_t *response)
{
if (iq->cb != NULL) {
iq->cb(s, iq->cb_data, iq->request, response, success);
}
- xmlFreeNode(iq->request);
+ rexmpp_xml_free(iq->request);
free(iq);
}
@@ -803,7 +771,7 @@ void rexmpp_done (rexmpp_t *s) {
rexmpp_dns_ctx_deinit(s);
xmlFreeParserCtxt(s->xml_parser);
if (s->jingle_rtp_description != NULL) {
- xmlFreeNode(s->jingle_rtp_description);
+ rexmpp_xml_free(s->jingle_rtp_description);
s->jingle_rtp_description = NULL;
}
if (s->stream_id != NULL) {
@@ -811,15 +779,15 @@ void rexmpp_done (rexmpp_t *s) {
s->stream_id = NULL;
}
if (s->roster_items != NULL) {
- xmlFreeNodeList(s->roster_items);
+ rexmpp_xml_free_list(s->roster_items);
s->roster_items = NULL;
}
if (s->roster_presence != NULL) {
- xmlFreeNodeList(s->roster_presence);
+ rexmpp_xml_free_list(s->roster_presence);
s->roster_presence = NULL;
}
if (s->roster_events != NULL) {
- xmlFreeNodeList(s->roster_events);
+ rexmpp_xml_free_list(s->roster_events);
s->roster_events = NULL;
}
if (s->roster_ver != NULL) {
@@ -827,11 +795,11 @@ void rexmpp_done (rexmpp_t *s) {
s->roster_ver = NULL;
}
if (s->disco_info != NULL) {
- xmlFreeNodeList(s->disco_info);
+ rexmpp_xml_free_list(s->disco_info);
s->disco_info = NULL;
}
if (s->stanza_queue != NULL) {
- xmlFreeNodeList(s->stanza_queue);
+ rexmpp_xml_free_list(s->stanza_queue);
s->stanza_queue = NULL;
}
while (s->active_iq != NULL) {
@@ -841,7 +809,7 @@ void rexmpp_done (rexmpp_t *s) {
rexmpp_iq_finish(s, iq, 0, NULL);
}
if (s->iq_cache != NULL) {
- xmlFreeNodeList(s->iq_cache);
+ rexmpp_xml_free_list(s->iq_cache);
s->iq_cache = NULL;
}
}
@@ -894,87 +862,7 @@ char *rexmpp_gen_id (rexmpp_t *s) {
return buf_base64;
}
-xmlNodePtr rexmpp_xml_add_id (rexmpp_t *s, xmlNodePtr node) {
- char *buf = rexmpp_gen_id(s);
- if (buf == NULL) {
- return NULL;
- }
- xmlNewProp(node, "id", buf);
- free(buf);
- return node;
-}
-
-unsigned int rexmpp_xml_siblings_count (xmlNodePtr node) {
- unsigned int i;
- for (i = 0; node != NULL; i++) {
- node = xmlNextElementSibling(node);
- }
- return i;
-}
-
-int rexmpp_xml_match (xmlNodePtr node,
- const char *namespace,
- const char *name)
-{
- if (node == NULL) {
- return 0;
- }
- if (name != NULL) {
- if (strcmp(name, node->name) != 0) {
- return 0;
- }
- }
- if (namespace != NULL) {
- if (node->nsDef == NULL || node->nsDef->href == NULL) {
- if (strcmp(namespace, "jabber:client") != 0) {
- return 0;
- }
- } else {
- if (node->nsDef) {
- if (strcmp(namespace, node->nsDef->href) != 0) {
- return 0;
- }
- } else {
- if (namespace != NULL) {
- return 0;
- }
- }
- }
- }
- return 1;
-}
-
-int rexmpp_xml_eq (xmlNodePtr n1, xmlNodePtr n2) {
- /* Just serialize and compare strings for now: awkward, but
- simple. */
- char *n1str = rexmpp_xml_serialize(n1);
- char *n2str = rexmpp_xml_serialize(n2);
- int eq = (strcmp(n1str, n2str) == 0);
- free(n1str);
- free(n2str);
- return eq;
-}
-
-xmlNodePtr rexmpp_xml_find_child (xmlNodePtr node,
- const char *namespace,
- const char *name)
-{
- if (node == NULL) {
- return NULL;
- }
- xmlNodePtr child;
- for (child = xmlFirstElementChild(node);
- child != NULL;
- child = xmlNextElementSibling(child))
- {
- if (rexmpp_xml_match(child, namespace, name)) {
- return child;
- }
- }
- return NULL;
-}
-
-xmlNodePtr rexmpp_xml_set_delay (rexmpp_t *s, xmlNodePtr node) {
+rexmpp_xml_t *rexmpp_xml_set_delay (rexmpp_t *s, rexmpp_xml_t *node) {
if (rexmpp_xml_find_child (node, NULL, "delay")) {
return node;
}
@@ -983,42 +871,15 @@ xmlNodePtr rexmpp_xml_set_delay (rexmpp_t *s, xmlNodePtr node) {
struct tm utc_time;
gmtime_r(&t, &utc_time);
strftime(buf, 42, "%FT%TZ", &utc_time);
- xmlNodePtr delay = xmlNewChild(node, NULL, "delay", NULL);
- xmlNewProp(delay, "stamp", buf);
+ rexmpp_xml_t *delay = rexmpp_xml_new_elem("delay", NULL);
+ rexmpp_xml_add_child(node, delay);
+ rexmpp_xml_add_attr(delay, "stamp", buf);
if (s != NULL && s->assigned_jid.full[0]) {
- xmlNewProp(delay, "from", s->assigned_jid.full);
+ rexmpp_xml_add_attr(delay, "from", s->assigned_jid.full);
}
return node;
}
-xmlNodePtr rexmpp_xml_parse (const char *str, int str_len) {
- xmlNodePtr elem = NULL;
- xmlDocPtr doc = xmlReadMemory(str, str_len, "", "utf-8", XML_PARSE_NONET);
- if (doc != NULL) {
- elem = xmlCopyNode(xmlDocGetRootElement(doc), 1);
- xmlFreeDoc(doc);
- }
- return elem;
-}
-
-char *rexmpp_xml_serialize (xmlNodePtr node) {
- xmlBufferPtr buf = xmlBufferCreate();
- xmlSaveCtxtPtr ctx = xmlSaveToBuffer(buf, "utf-8", 0);
- xmlSaveTree(ctx, node);
- xmlSaveFlush(ctx);
- xmlSaveClose(ctx);
- unsigned char *out = xmlBufferDetach(buf);
- xmlBufferFree(buf);
- return out;
-}
-
-int rexmpp_xml_is_stanza (xmlNodePtr node) {
- return rexmpp_xml_match(node, "jabber:client", "message") ||
- rexmpp_xml_match(node, "jabber:client", "iq") ||
- rexmpp_xml_match(node, "jabber:client", "presence");
-}
-
-
rexmpp_err_t rexmpp_send_start (rexmpp_t *s, const void *data, size_t data_len)
{
int sasl_err;
@@ -1074,15 +935,15 @@ rexmpp_err_t rexmpp_send_continue (rexmpp_t *s)
free(s->send_buffer);
s->send_buffer = NULL;
if (s->send_queue != NULL) {
- xmlNodePtr node = s->send_queue;
+ rexmpp_xml_t *node = s->send_queue;
unsigned char *buf = rexmpp_xml_serialize(node);
ret = rexmpp_send_start(s, buf, strlen(buf));
free(buf);
if (ret != REXMPP_SUCCESS) {
return ret;
}
- s->send_queue = xmlNextElementSibling(s->send_queue);
- xmlFreeNode(node);
+ s->send_queue = s->send_queue->next;
+ rexmpp_xml_free(node);
} else {
return REXMPP_SUCCESS;
}
@@ -1122,19 +983,19 @@ rexmpp_err_t rexmpp_send_raw (rexmpp_t *s, const void *data, size_t data_len)
rexmpp_err_t rexmpp_sm_send_req (rexmpp_t *s);
-rexmpp_err_t rexmpp_send (rexmpp_t *s, xmlNodePtr node)
+rexmpp_err_t rexmpp_send (rexmpp_t *s, rexmpp_xml_t *node)
{
int need_ack = 0;
int ret;
if (s->xml_out_cb != NULL && s->xml_out_cb(s, node) == 1) {
- xmlFreeNode(node);
+ rexmpp_xml_free(node);
rexmpp_log(s, LOG_WARNING, "Message sending was cancelled by xml_out_cb.");
return REXMPP_E_CANCELLED;
}
if (rexmpp_xml_siblings_count(s->send_queue) >= s->send_queue_size) {
- xmlFreeNode(node);
+ rexmpp_xml_free(node);
rexmpp_log(s, LOG_ERR, "The send queue is full, not sending.");
return REXMPP_E_SEND_QUEUE_FULL;
}
@@ -1145,20 +1006,21 @@ rexmpp_err_t rexmpp_send (rexmpp_t *s, xmlNodePtr node)
if (s->sm_state == REXMPP_SM_ACTIVE) {
if (s->stanzas_out_count >=
s->stanza_queue_size + s->stanzas_out_acknowledged) {
- xmlFreeNode(node);
+ rexmpp_xml_free(node);
rexmpp_log(s, LOG_ERR, "The stanza queue is full, not sending.");
return REXMPP_E_STANZA_QUEUE_FULL;
}
need_ack = 1;
- xmlNodePtr queued_stanza = rexmpp_xml_set_delay(s, xmlCopyNode(node, 1));
+ rexmpp_xml_t *queued_stanza =
+ rexmpp_xml_set_delay(s, rexmpp_xml_clone(node));
if (s->stanza_queue == NULL) {
s->stanza_queue = queued_stanza;
} else {
- xmlNodePtr last = s->stanza_queue;
- while (xmlNextElementSibling(last) != NULL) {
- last = xmlNextElementSibling(last);
+ rexmpp_xml_t *last = s->stanza_queue;
+ while (last->next != NULL) {
+ last = last->next;
}
- xmlAddNextSibling(last, queued_stanza);
+ last->next = queued_stanza;
}
}
if (s->sm_state != REXMPP_SM_INACTIVE) {
@@ -1170,7 +1032,7 @@ rexmpp_err_t rexmpp_send (rexmpp_t *s, xmlNodePtr node)
unsigned char *buf = rexmpp_xml_serialize(node);
ret = rexmpp_send_raw(s, buf, strlen(buf));
free(buf);
- xmlFreeNode(node);
+ rexmpp_xml_free(node);
if (ret != REXMPP_SUCCESS && ret != REXMPP_E_AGAIN) {
return ret;
}
@@ -1178,11 +1040,11 @@ rexmpp_err_t rexmpp_send (rexmpp_t *s, xmlNodePtr node)
if (s->send_queue == NULL) {
s->send_queue = node;
} else {
- xmlNodePtr last = s->send_queue;
- while (xmlNextElementSibling(last) != NULL) {
- last = xmlNextElementSibling(last);
+ rexmpp_xml_t *last = s->send_queue;
+ while (last->next != NULL) {
+ last = last->next;
}
- xmlAddNextSibling(last, node);
+ last->next = node;
}
ret = REXMPP_E_AGAIN;
}
@@ -1193,28 +1055,25 @@ rexmpp_err_t rexmpp_send (rexmpp_t *s, xmlNodePtr node)
}
void rexmpp_iq_reply (rexmpp_t *s,
- xmlNodePtr req,
+ rexmpp_xml_t *req,
const char *type,
- xmlNodePtr payload)
+ rexmpp_xml_t *payload)
{
- xmlNodePtr iq_stanza = xmlNewNode(NULL, "iq");
- xmlNewNs(iq_stanza, "jabber:client", NULL);
- xmlNewProp(iq_stanza, "type", type);
- char *id = xmlGetProp(req, "id");
+ rexmpp_xml_t *iq_stanza = rexmpp_xml_new_elem("iq", "jabber:client");
+ rexmpp_xml_add_attr(iq_stanza, "type", type);
+ const char *id = rexmpp_xml_find_attr_val(req, "id");
if (id != NULL) {
- xmlNewProp(iq_stanza, "id", id);
- free(id);
+ rexmpp_xml_add_attr(iq_stanza, "id", id);
}
- char *to = xmlGetProp(req, "from");
+ const char *to = rexmpp_xml_find_attr_val(req, "from");
if (to != NULL) {
- xmlNewProp(iq_stanza, "to", to);
- free(to);
+ rexmpp_xml_add_attr(iq_stanza, "to", to);
}
if (s->assigned_jid.full[0]) {
- xmlNewProp(iq_stanza, "from", s->assigned_jid.full);
+ rexmpp_xml_add_attr(iq_stanza, "from", s->assigned_jid.full);
}
if (payload != NULL) {
- xmlAddChild(iq_stanza, payload);
+ rexmpp_xml_add_child(iq_stanza, payload);
}
rexmpp_send(s, iq_stanza);
}
@@ -1222,7 +1081,7 @@ void rexmpp_iq_reply (rexmpp_t *s,
rexmpp_err_t rexmpp_iq_new (rexmpp_t *s,
const char *type,
const char *to,
- xmlNodePtr payload,
+ rexmpp_xml_t *payload,
rexmpp_iq_callback_t cb,
void *cb_data)
{
@@ -1239,18 +1098,19 @@ rexmpp_err_t rexmpp_iq_new (rexmpp_t *s,
rexmpp_iq_finish(s, last, 0, NULL);
}
- xmlNodePtr iq_stanza = rexmpp_xml_add_id(s, xmlNewNode(NULL, "iq"));
- xmlNewNs(iq_stanza, "jabber:client", NULL);
- xmlNewProp(iq_stanza, "type", type);
+ rexmpp_xml_t *iq_stanza =
+ rexmpp_xml_new_elem("iq", "jabber:client");
+ rexmpp_xml_add_id(s, iq_stanza);
+ rexmpp_xml_add_attr(iq_stanza, "type", type);
if (to != NULL) {
- xmlNewProp(iq_stanza, "to", to);
+ rexmpp_xml_add_attr(iq_stanza, "to", to);
}
if (s->assigned_jid.full[0]) {
- xmlNewProp(iq_stanza, "from", s->assigned_jid.full);
+ rexmpp_xml_add_attr(iq_stanza, "from", s->assigned_jid.full);
}
- xmlAddChild(iq_stanza, payload);
+ rexmpp_xml_add_child(iq_stanza, payload);
rexmpp_iq_t *iq = malloc(sizeof(rexmpp_iq_t));
- iq->request = xmlCopyNode(iq_stanza, 1);
+ iq->request = rexmpp_xml_clone(iq_stanza);
iq->cb = cb;
iq->cb_data = cb_data;
iq->next = s->active_iq;
@@ -1260,12 +1120,12 @@ rexmpp_err_t rexmpp_iq_new (rexmpp_t *s,
void rexmpp_iq_cache_cb (rexmpp_t *s,
void *cb_data,
- xmlNodePtr request,
- xmlNodePtr response,
+ rexmpp_xml_t *request,
+ rexmpp_xml_t *response,
int success)
{
if (success && response != NULL) {
- xmlNodePtr prev_last = NULL, last = NULL, ciq = s->iq_cache;
+ rexmpp_xml_t *prev_last = NULL, *last = NULL, *ciq = s->iq_cache;
uint32_t size = 0;
while (ciq != NULL && ciq->next != NULL) {
prev_last = last;
@@ -1274,12 +1134,12 @@ void rexmpp_iq_cache_cb (rexmpp_t *s,
ciq = ciq->next->next;
}
if (size >= s->iq_queue_size && prev_last != NULL) {
- xmlFreeNode(last->next);
- xmlFreeNode(last);
+ rexmpp_xml_free(last->next);
+ rexmpp_xml_free(last);
prev_last->next->next = NULL;
}
- xmlNodePtr req = xmlCopyNode(request, 1);
- xmlNodePtr resp = xmlCopyNode(response, 1);
+ rexmpp_xml_t *req = rexmpp_xml_clone(request);
+ rexmpp_xml_t *resp = rexmpp_xml_clone(response);
req->next = resp;
resp->next = s->iq_cache;
s->iq_cache = req;
@@ -1294,24 +1154,22 @@ void rexmpp_iq_cache_cb (rexmpp_t *s,
rexmpp_err_t rexmpp_cached_iq_new (rexmpp_t *s,
const char *type,
const char *to,
- xmlNodePtr payload,
+ rexmpp_xml_t *payload,
rexmpp_iq_callback_t cb,
void *cb_data,
int fresh)
{
if (! fresh) {
- xmlNodePtr ciq = s->iq_cache;
+ rexmpp_xml_t *ciq = s->iq_cache;
while (ciq != NULL && ciq->next != NULL) {
- xmlNodePtr ciq_pl = xmlFirstElementChild(ciq);
- char *ciq_type = xmlGetProp(ciq, "type");
- char *ciq_to = xmlGetProp(ciq, "to");
+ rexmpp_xml_t *ciq_pl = ciq->alt.elem.children;
+ const char *ciq_type = rexmpp_xml_find_attr_val(ciq, "type");
+ const char *ciq_to = rexmpp_xml_find_attr_val(ciq, "to");
int matches = (rexmpp_xml_eq(ciq_pl, payload) &&
strcmp(ciq_type, type) == 0 &&
strcmp(ciq_to, to) == 0);
- free(ciq_to);
- free(ciq_type);
if (matches) {
- xmlFreeNode(payload);
+ rexmpp_xml_free(payload);
if (cb != NULL) {
cb(s, cb_data, ciq, ciq->next, 1);
}
@@ -1329,20 +1187,18 @@ rexmpp_err_t rexmpp_cached_iq_new (rexmpp_t *s,
rexmpp_err_t rexmpp_sm_ack (rexmpp_t *s) {
char buf[11];
- xmlNodePtr ack = xmlNewNode(NULL, "a");
- xmlNewNs(ack, "urn:xmpp:sm:3", NULL);
+ rexmpp_xml_t *ack = rexmpp_xml_new_elem("a", "urn:xmpp:sm:3");
snprintf(buf, 11, "%u", s->stanzas_in_count);
- xmlNewProp(ack, "h", buf);
+ rexmpp_xml_add_attr(ack, "h", buf);
return rexmpp_send(s, ack);
}
rexmpp_err_t rexmpp_sm_send_req (rexmpp_t *s) {
- xmlNodePtr ack = xmlNewNode(NULL, "r");
- xmlNewNs(ack, "urn:xmpp:sm:3", NULL);
- return rexmpp_send(s, ack);
+ rexmpp_xml_t *req = rexmpp_xml_new_elem("r", "urn:xmpp:sm:3");
+ return rexmpp_send(s, req);
}
-rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem);
+rexmpp_err_t rexmpp_process_element (rexmpp_t *s, rexmpp_xml_t *elem);
rexmpp_err_t rexmpp_recv (rexmpp_t *s) {
char chunk_raw[4096], *chunk;
@@ -1387,12 +1243,14 @@ rexmpp_err_t rexmpp_recv (rexmpp_t *s) {
elem != NULL && (err == REXMPP_SUCCESS || err == REXMPP_E_AGAIN);
elem = elem->next)
{
- if (s->xml_in_cb != NULL && s->xml_in_cb(s, elem) != 0) {
+ rexmpp_xml_t *elem_tmp = rexmpp_xml_from_libxml2(elem);
+ if (s->xml_in_cb != NULL && s->xml_in_cb(s, elem_tmp) != 0) {
rexmpp_log(s, LOG_WARNING,
"Message processing was cancelled by xml_in_cb.");
} else {
- err = rexmpp_process_element(s, elem);
+ err = rexmpp_process_element(s, elem_tmp);
}
+ rexmpp_xml_free(elem_tmp);
}
xmlFreeNodeList(s->input_queue);
s->input_queue = NULL;
@@ -1632,10 +1490,10 @@ void rexmpp_srv_cb (rexmpp_t *s,
rexmpp_err_t rexmpp_resend_stanzas (rexmpp_t *s) {
uint32_t i, count;
rexmpp_err_t ret = REXMPP_SUCCESS;
- xmlNodePtr sq;
+ rexmpp_xml_t *sq;
count = s->stanzas_out_count - s->stanzas_out_acknowledged;
for (i = 0; i < count && s->stanza_queue != NULL; i++) {
- sq = xmlNextElementSibling(s->stanza_queue);
+ sq = s->stanza_queue->next;
ret = rexmpp_send(s, s->stanza_queue);
if (ret > REXMPP_E_AGAIN) {
return ret;
@@ -1652,12 +1510,11 @@ rexmpp_err_t rexmpp_resend_stanzas (rexmpp_t *s) {
return ret;
}
-void rexmpp_sm_handle_ack (rexmpp_t *s, xmlNodePtr elem) {
- char *h = xmlGetProp(elem, "h");
+void rexmpp_sm_handle_ack (rexmpp_t *s, rexmpp_xml_t *elem) {
+ const char *h = rexmpp_xml_find_attr_val(elem, "h");
if (h != NULL) {
uint32_t prev_ack = s->stanzas_out_acknowledged;
s->stanzas_out_acknowledged = strtoul(h, NULL, 10);
- xmlFree(h);
rexmpp_log(s, LOG_DEBUG,
"server acknowledged %u out of %u sent stanzas",
s->stanzas_out_acknowledged,
@@ -1666,8 +1523,8 @@ void rexmpp_sm_handle_ack (rexmpp_t *s, xmlNodePtr elem) {
if (prev_ack <= s->stanzas_out_acknowledged) {
uint32_t i;
for (i = prev_ack; i < s->stanzas_out_acknowledged; i++) {
- xmlNodePtr sq = xmlNextElementSibling(s->stanza_queue);
- xmlFreeNode(s->stanza_queue);
+ rexmpp_xml_t *sq = s->stanza_queue->next;
+ rexmpp_xml_free(s->stanza_queue);
s->stanza_queue = sq;
}
} else {
@@ -1686,8 +1543,8 @@ void rexmpp_sm_handle_ack (rexmpp_t *s, xmlNodePtr elem) {
void rexmpp_carbons_enabled (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
@@ -1704,8 +1561,8 @@ void rexmpp_carbons_enabled (rexmpp_t *s,
void rexmpp_pong (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
@@ -1717,15 +1574,15 @@ void rexmpp_pong (rexmpp_t *s,
void rexmpp_disco_carbons_cb (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success) {
(void)ptr;
(void)req;
(void)response;
if (success) {
- xmlNodePtr carbons_enable =
- rexmpp_xml_new_node("enable", "urn:xmpp:carbons:2");
+ rexmpp_xml_t *carbons_enable =
+ rexmpp_xml_new_elem("enable", "urn:xmpp:carbons:2");
s->carbons_state = REXMPP_CARBONS_NEGOTIATION;
rexmpp_iq_new(s, "set", NULL, carbons_enable,
rexmpp_carbons_enabled, NULL);
@@ -1748,27 +1605,31 @@ void rexmpp_stream_is_ready(rexmpp_t *s) {
if (s->roster_cache_file != NULL) {
rexmpp_roster_cache_read(s);
}
- xmlNodePtr roster_query = xmlNewNode(NULL, "query");
- xmlNewNs(roster_query, "jabber:iq:roster", NULL);
+ rexmpp_xml_t *roster_query =
+ rexmpp_xml_new_elem("query", "jabber:iq:roster");
if (s->roster_ver != NULL) {
- xmlNewProp(roster_query, "ver", s->roster_ver);
+ rexmpp_xml_add_attr(roster_query, "ver", s->roster_ver);
} else {
- xmlNewProp(roster_query, "ver", "");
+ rexmpp_xml_add_attr(roster_query, "ver", "");
}
rexmpp_iq_new(s, "get", NULL,
roster_query, rexmpp_iq_roster_get, NULL);
}
- xmlNodePtr presence = rexmpp_xml_add_id(s, xmlNewNode(NULL, "presence"));
+ rexmpp_xml_t *presence =
+ rexmpp_xml_new_elem("presence", "jabber:client");
+ rexmpp_xml_add_id(s, presence);
+
char *caps_hash = rexmpp_capabilities_hash(s, rexmpp_disco_info(s));
if (caps_hash != NULL) {
- xmlNodePtr c = xmlNewNode(NULL, "c");
- xmlNewNs(c, "http://jabber.org/protocol/caps", NULL);
- xmlNewProp(c, "hash", "sha-1");
- xmlNewProp(c, "node", s->disco_node);
- xmlNewProp(c, "ver", caps_hash);
- xmlAddChild(presence, c);
+ rexmpp_xml_t *c =
+ rexmpp_xml_new_elem("c", "http://jabber.org/protocol/caps");
+ rexmpp_xml_add_attr(c, "hash", "sha-1");
+ rexmpp_xml_add_attr(c, "node", s->disco_node);
+ rexmpp_xml_add_attr(c, "ver", caps_hash);
+ rexmpp_xml_add_child(presence, c);
free(caps_hash);
}
+
rexmpp_send(s, presence);
}
@@ -1776,8 +1637,8 @@ void rexmpp_stream_is_ready(rexmpp_t *s) {
https://tools.ietf.org/html/rfc6120#section-7 */
void rexmpp_bound (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
@@ -1788,24 +1649,22 @@ void rexmpp_bound (rexmpp_t *s,
return;
}
/* todo: handle errors */
- xmlNodePtr child = xmlFirstElementChild(response);
+ rexmpp_xml_t *child = rexmpp_xml_first_elem_child(response);
if (rexmpp_xml_match(child, "urn:ietf:params:xml:ns:xmpp-bind", "bind")) {
- xmlNodePtr jid = xmlFirstElementChild(child);
+ rexmpp_xml_t *jid = rexmpp_xml_first_elem_child(child);
if (rexmpp_xml_match(jid, "urn:ietf:params:xml:ns:xmpp-bind", "jid")) {
- char *jid_str = xmlNodeGetContent(jid);
+ const char *jid_str = rexmpp_xml_text_child(jid);
rexmpp_log(s, LOG_INFO, "jid: %s", jid_str);
rexmpp_jid_parse(jid_str, &(s->assigned_jid));
- free(jid_str);
}
if (s->stream_id == NULL &&
- (child = rexmpp_xml_find_child(s->stream_features, "urn:xmpp:sm:3",
- "sm"))) {
+ (rexmpp_xml_find_child(s->stream_features, "urn:xmpp:sm:3",
+ "sm") != NULL)) {
/* Try to resume a stream. */
s->sm_state = REXMPP_SM_NEGOTIATION;
s->stream_state = REXMPP_STREAM_SM_FULL;
- xmlNodePtr sm_enable = xmlNewNode(NULL, "enable");
- xmlNewNs(sm_enable, "urn:xmpp:sm:3", NULL);
- xmlNewProp(sm_enable, "resume", "true");
+ rexmpp_xml_t *sm_enable =
+ rexmpp_xml_new_elem("enable", "urn:xmpp:sm:3");
rexmpp_send(s, sm_enable);
s->stanzas_out_count = 0;
s->stanzas_out_acknowledged = 0;
@@ -1820,12 +1679,12 @@ void rexmpp_bound (rexmpp_t *s,
rexmpp_err_t rexmpp_stream_bind (rexmpp_t *s) {
/* Issue a bind request. */
s->stream_state = REXMPP_STREAM_BIND;
- xmlNodePtr bind_cmd = xmlNewNode(NULL, "bind");
- xmlNewNs(bind_cmd, "urn:ietf:params:xml:ns:xmpp-bind", NULL);
+ rexmpp_xml_t *bind_cmd =
+ rexmpp_xml_new_elem("bind", "urn:ietf:params:xml:ns:xmpp-bind");
return rexmpp_iq_new(s, "set", NULL, bind_cmd, rexmpp_bound, NULL);
}
-rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
+rexmpp_err_t rexmpp_process_element (rexmpp_t *s, rexmpp_xml_t *elem) {
rexmpp_console_on_recv(s, elem);
/* Stream negotiation,
@@ -1835,22 +1694,23 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
/* Remember features. */
if (s->stream_features != NULL) {
- xmlFreeNode(s->stream_features);
+ rexmpp_xml_free(s->stream_features);
}
- s->stream_features = xmlCopyNode(elem, 1);
+ s->stream_features = rexmpp_xml_clone(elem);
/* TODO: check for required features properly here. Currently
assuming that STARTTLS, SASL, and BIND (with an exception for
SM) are always required if they are present. */
- xmlNodePtr starttls =
+ rexmpp_xml_t *starttls =
rexmpp_xml_find_child(elem, "urn:ietf:params:xml:ns:xmpp-tls",
"starttls");
- xmlNodePtr sasl =
+ rexmpp_xml_t *sasl =
rexmpp_xml_find_child(elem, "urn:ietf:params:xml:ns:xmpp-sasl",
"mechanisms");
- xmlNodePtr bind =
+ rexmpp_xml_t *bind =
rexmpp_xml_find_child(elem, "urn:ietf:params:xml:ns:xmpp-bind", "bind");
- xmlNodePtr sm = rexmpp_xml_find_child(elem, "urn:xmpp:sm:3", "sm");
+ rexmpp_xml_t *sm =
+ rexmpp_xml_find_child(elem, "urn:xmpp:sm:3", "sm");
if (starttls != NULL) {
/* Go for TLS, unless we're both trying to avoid it, and have
@@ -1858,8 +1718,8 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
if (! (s->tls_policy == REXMPP_TLS_AVOID &&
(sasl != NULL || bind != NULL || sm != NULL))) {
s->stream_state = REXMPP_STREAM_STARTTLS;
- xmlNodePtr starttls_cmd = xmlNewNode(NULL, "starttls");
- xmlNewNs(starttls_cmd, "urn:ietf:params:xml:ns:xmpp-tls", NULL);
+ rexmpp_xml_t *starttls_cmd =
+ rexmpp_xml_new_elem("starttls", "urn:ietf:params:xml:ns:xmpp-tls");
rexmpp_send(s, starttls_cmd);
return REXMPP_SUCCESS;
}
@@ -1873,7 +1733,7 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
}
/* Nothing to negotiate. */
- if (xmlFirstElementChild(elem) == NULL) {
+ if (rexmpp_xml_first_elem_child(elem) == NULL) {
rexmpp_stream_is_ready(s);
return REXMPP_SUCCESS;
}
@@ -1883,18 +1743,17 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
s->sasl_state = REXMPP_SASL_NEGOTIATION;
char mech_list[2048]; /* todo: perhaps grow it dynamically */
mech_list[0] = '\0';
- xmlNodePtr mechanism;
- for (mechanism = xmlFirstElementChild(sasl);
+ rexmpp_xml_t *mechanism;
+ for (mechanism = rexmpp_xml_first_elem_child(sasl);
mechanism != NULL;
- mechanism = xmlNextElementSibling(mechanism)) {
+ mechanism = rexmpp_xml_next_elem_sibling(mechanism)) {
if (rexmpp_xml_match(mechanism, "urn:ietf:params:xml:ns:xmpp-sasl",
"mechanism")) {
- char *mech_str = xmlNodeGetContent(mechanism);
+ const char *mech_str = rexmpp_xml_text_child(mechanism);
snprintf(mech_list + strlen(mech_list),
2048 - strlen(mech_list),
"%s ",
mech_str);
- free(mech_str);
}
}
const char *mech = rexmpp_sasl_suggest_mechanism(s, mech_list);
@@ -1913,10 +1772,10 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
s->sasl_state = REXMPP_SASL_ERROR;
return REXMPP_E_SASL;
}
- xmlNodePtr auth_cmd = xmlNewNode(NULL, "auth");
- xmlNewProp(auth_cmd, "mechanism", mech);
- xmlNewNs(auth_cmd, "urn:ietf:params:xml:ns:xmpp-sasl", NULL);
- xmlNodeAddContent(auth_cmd, sasl_buf);
+ rexmpp_xml_t *auth_cmd =
+ rexmpp_xml_new_elem("auth", "urn:ietf:params:xml:ns:xmpp-sasl");
+ rexmpp_xml_add_attr(auth_cmd, "mechanism", mech);
+ rexmpp_xml_add_text(auth_cmd, sasl_buf);
free(sasl_buf);
rexmpp_send(s, auth_cmd);
return REXMPP_SUCCESS;
@@ -1926,10 +1785,10 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
s->stream_state = REXMPP_STREAM_SM_RESUME;
char buf[11];
snprintf(buf, 11, "%u", s->stanzas_in_count);
- xmlNodePtr sm_resume = xmlNewNode(NULL, "resume");
- xmlNewNs(sm_resume, "urn:xmpp:sm:3", NULL);
- xmlNewProp(sm_resume, "previd", s->stream_id);
- xmlNewProp(sm_resume, "h", buf);
+ rexmpp_xml_t *sm_resume =
+ rexmpp_xml_new_elem("resume", "urn:xmpp:sm:3");
+ rexmpp_xml_add_attr(sm_resume, "previd", s->stream_id);
+ rexmpp_xml_add_attr(sm_resume, "h", buf);
rexmpp_send(s, sm_resume);
return REXMPP_SUCCESS;
}
@@ -1938,7 +1797,8 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
return rexmpp_stream_bind(s);
}
} else {
- rexmpp_log(s, LOG_ERR, "Expected stream features, received %s", elem->name);
+ rexmpp_log(s, LOG_ERR, "Expected stream features, received %s",
+ elem->alt.elem.qname.name);
return REXMPP_E_STREAM;
}
}
@@ -1948,18 +1808,18 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
should cancel further processing by the library (so we can send
errors for unhandled IQs here). */
if (rexmpp_xml_match(elem, "jabber:client", "iq")) {
- char *type = xmlGetProp(elem, "type");
+ const char *type = rexmpp_xml_find_attr_val(elem, "type");
/* IQ responses. */
if (strcmp(type, "result") == 0 || strcmp(type, "error") == 0) {
- char *id = xmlGetProp(elem, "id");
+ const char *id = rexmpp_xml_find_attr_val(elem, "id");
rexmpp_iq_t *req = s->active_iq, *prev_req = NULL;
int found = 0;
while (req != NULL && found == 0) {
- char *req_id = xmlGetProp(req->request, "id");
- char *req_to = xmlGetProp(req->request, "to");
- char *rep_from = xmlGetProp(elem, "from");
+ const char *req_id = rexmpp_xml_find_attr_val(req->request, "id");
+ const char *req_to = rexmpp_xml_find_attr_val(req->request, "to");
+ const char *rep_from = rexmpp_xml_find_attr_val(elem, "from");
rexmpp_iq_t *req_next = req->next;
- int id_matches = (strcmp(id, req_id) == 0);
+ int id_matches = (req_id != NULL) && (strcmp(id, req_id) == 0);
int jid_matches = 0;
if (rep_from == NULL) {
jid_matches = 1;
@@ -1981,29 +1841,20 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
/* Finish and free the IQ request structure. */
rexmpp_iq_finish(s, req, success, elem);
}
- if (req_to != NULL) {
- free(req_to);
- }
- if (rep_from != NULL) {
- free(rep_from);
- }
- free(req_id);
prev_req = req;
req = req_next;
}
- free(id);
} else if (! rexmpp_jingle_iq(s, elem)) {
if (strcmp(type, "set") == 0) {
- xmlNodePtr query = xmlFirstElementChild(elem);
+ rexmpp_xml_t *query = rexmpp_xml_first_elem_child(elem);
int from_server = 0;
- char *from = xmlGetProp(elem, "from");
+ const char *from = rexmpp_xml_find_attr_val(elem, "from");
if (from == NULL) {
from_server = 1;
} else {
if (strcmp(from, s->initial_jid.domain) == 0) {
from_server = 1;
}
- free(from);
}
if (from_server &&
s->manage_roster &&
@@ -2012,8 +1863,8 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
if (s->roster_ver != NULL) {
free(s->roster_ver);
}
- s->roster_ver = xmlGetProp(query, "ver");
- rexmpp_modify_roster(s, xmlFirstElementChild(query));
+ s->roster_ver = strdup(rexmpp_xml_find_attr_val(query, "ver"));
+ rexmpp_modify_roster(s, rexmpp_xml_first_elem_child(query));
/* todo: check for errors */
rexmpp_iq_reply(s, elem, "result", NULL);
if (s->roster_cache_file != NULL) {
@@ -2025,9 +1876,9 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
rexmpp_xml_error("cancel", "service-unavailable"));
}
} else if (strcmp(type, "get") == 0) {
- xmlNodePtr query = xmlFirstElementChild(elem);
+ rexmpp_xml_t *query = rexmpp_xml_first_elem_child(elem);
if (rexmpp_xml_match(query, "http://jabber.org/protocol/disco#info", "query")) {
- char *node = xmlGetProp(query, "node");
+ const char *node = rexmpp_xml_find_attr_val(query, "node");
char *caps_hash = rexmpp_capabilities_hash(s, rexmpp_disco_info(s));
if (node == NULL ||
(caps_hash != NULL &&
@@ -2036,12 +1887,13 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
strncmp(node, s->disco_node, strlen(s->disco_node)) == 0 &&
node[strlen(s->disco_node)] == '#' &&
strcmp(node + strlen(s->disco_node) + 1, caps_hash) == 0)) {
- xmlNodePtr result = xmlNewNode(NULL, "query");
- xmlNewNs(result, "http://jabber.org/protocol/disco#info", NULL);
+ rexmpp_xml_t *result =
+ rexmpp_xml_new_elem("query", "http://jabber.org/protocol/disco#info");
if (node != NULL) {
- xmlNewProp(result, "node", node);
+ rexmpp_xml_add_attr(result, "node", node);
}
- xmlAddChild(result, xmlCopyNodeList(rexmpp_disco_info(s)));
+ rexmpp_xml_add_child(result,
+ rexmpp_xml_clone_list(rexmpp_disco_info(s)));
rexmpp_iq_reply(s, elem, "result", result);
} else {
rexmpp_log(s, LOG_WARNING,
@@ -2052,20 +1904,17 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
if (caps_hash != NULL) {
free(caps_hash);
}
- if (node != NULL) {
- free(node);
- }
} else if (rexmpp_xml_match(query, "urn:xmpp:ping", "ping")) {
rexmpp_iq_reply(s, elem, "result", NULL);
} else if (rexmpp_xml_match(query, "jabber:iq:version", "query")) {
- xmlNodePtr reply = xmlNewNode(NULL, "query");
- xmlNewNs(reply, "jabber:iq:version", NULL);
- xmlNodePtr name = xmlNewNode(NULL, "name");
- xmlNodeAddContent(name, s->client_name);
- xmlAddChild(reply, name);
- xmlNodePtr version = xmlNewNode(NULL, "version");
- xmlNodeAddContent(version, s->client_version);
- xmlAddChild(reply, version);
+ rexmpp_xml_t *reply =
+ rexmpp_xml_new_elem("query", "jabber:iq:version");
+ rexmpp_xml_t *name = rexmpp_xml_new_elem("name", NULL);
+ rexmpp_xml_add_text(name, s->client_name);
+ rexmpp_xml_add_child(reply, name);
+ rexmpp_xml_t *version = rexmpp_xml_new_elem("version", NULL);
+ rexmpp_xml_add_text(version, s->client_version);
+ rexmpp_xml_add_child(reply, version);
rexmpp_iq_reply(s, elem, "result", reply);
} else {
/* An unknown request. */
@@ -2074,49 +1923,44 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
}
}
}
- free(type);
}
/* Incoming presence information. */
if (rexmpp_xml_match(elem, "jabber:client", "presence") &&
s->manage_roster &&
s->track_roster_presence) {
- char *from = xmlGetProp(elem, "from");
+ const char *from = rexmpp_xml_find_attr_val(elem, "from");
if (from != NULL) {
struct rexmpp_jid from_jid;
rexmpp_jid_parse(from, &from_jid);
- xmlFree(from);
if (rexmpp_roster_find_item(s, from_jid.bare, NULL) != NULL) {
/* The bare JID is in the roster. */
- char *type = xmlGetProp(elem, "type");
- xmlNodePtr cur, prev;
+ const char *type = rexmpp_xml_find_attr_val(elem, "type");
+ rexmpp_xml_t *cur, *prev;
if (type == NULL || strcmp(type, "unavailable") == 0) {
/* Either a new "available" presence or an "unavailable"
one: remove the previously stored presence for this
JID. */
for (prev = NULL, cur = s->roster_presence;
cur != NULL;
- prev = cur, cur = xmlNextElementSibling(cur)) {
- char *cur_from = xmlGetProp(cur, "from");
+ prev = cur, cur = cur->next) {
+ const char *cur_from = rexmpp_xml_find_attr_val(cur, "from");
if (strcmp(cur_from, from_jid.full) == 0) {
if (prev == NULL) {
s->roster_presence = cur->next;
} else {
prev->next = cur->next;
}
- xmlFreeNode(cur);
- cur = NULL;
+ rexmpp_xml_free(cur);
+ break;
}
- free(cur_from);
}
}
if (type == NULL) {
/* An "available" presence: add it. */
- xmlNodePtr presence = xmlCopyNode(elem, 1);
+ rexmpp_xml_t *presence = rexmpp_xml_clone(elem);
presence->next = s->roster_presence;
s->roster_presence = presence;
- } else {
- free(type);
}
}
}
@@ -2124,28 +1968,27 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
/* Incoming messages. */
if (rexmpp_xml_match(elem, "jabber:client", "message")) {
- char *from = xmlGetProp(elem, "from");
+ const char *from = rexmpp_xml_find_attr_val(elem, "from");
if (from != NULL) {
struct rexmpp_jid from_jid;
rexmpp_jid_parse(from, &from_jid);
- xmlFree(from);
if (rexmpp_roster_find_item(s, from_jid.bare, NULL) != NULL ||
strcmp(from_jid.bare, s->assigned_jid.bare) == 0) {
- xmlNodePtr event =
+ rexmpp_xml_t *event =
rexmpp_xml_find_child(elem,
"http://jabber.org/protocol/pubsub#event",
"event");
if (event != NULL && s->manage_roster && s->track_roster_events) {
- xmlNodePtr items =
+ rexmpp_xml_t *items =
rexmpp_xml_find_child(event,
"http://jabber.org/protocol/pubsub#event",
"items");
if (items != NULL) {
- char *node = xmlGetProp(items, "node");
+ const char *node = rexmpp_xml_find_attr_val(items, "node");
if (node != NULL) {
/* Remove the previously stored items for the same sender
and node, if any. */
- xmlNodePtr prev, cur;
+ rexmpp_xml_t *prev, *cur;
cur = rexmpp_find_event(s, from_jid.bare, node, &prev);
if (cur) {
if (prev == NULL) {
@@ -2153,12 +1996,12 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
} else {
prev->next = cur->next;
}
- xmlFreeNode(cur);
+ rexmpp_xml_free(cur);
cur = NULL;
}
/* Add the new message. */
- xmlNodePtr message = xmlCopyNode(elem, 1);
+ rexmpp_xml_t *message = rexmpp_xml_clone(elem);
message->next = s->roster_events;
s->roster_events = message;
@@ -2170,56 +2013,54 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
if (s->autojoin_bookmarked_mucs &&
strcmp(node, "urn:xmpp:bookmarks:1") == 0 &&
strcmp(from_jid.bare, s->assigned_jid.bare) == 0) {
- xmlNodePtr item;
- for (item = xmlFirstElementChild(items);
+ rexmpp_xml_t *item;
+ for (item = rexmpp_xml_first_elem_child(items);
item != NULL;
- item = xmlNextElementSibling(item)) {
- xmlNodePtr conference =
+ item = rexmpp_xml_next_elem_sibling(item)) {
+ rexmpp_xml_t *conference =
rexmpp_xml_find_child(item,
"urn:xmpp:bookmarks:1",
"conference");
if (conference == NULL) {
continue;
}
- char *item_id = xmlGetProp(item, "id");
+ const char *item_id = rexmpp_xml_find_attr_val(item, "id");
if (item_id == NULL) {
continue;
}
- char *autojoin = xmlGetProp(conference, "autojoin");
+ const char *autojoin = rexmpp_xml_find_attr_val(conference, "autojoin");
if (autojoin == NULL) {
- free(item_id);
continue;
}
if (strcmp(autojoin, "true") == 0 ||
strcmp(autojoin, "1") == 0) {
- xmlNodePtr presence =
- rexmpp_xml_add_id(s, xmlNewNode(NULL, "presence"));
- xmlNewProp(presence, "from", s->assigned_jid.full);
- xmlNodePtr nick =
+ rexmpp_xml_t *presence =
+ rexmpp_xml_new_elem("presence", "jabber:client");
+ rexmpp_xml_add_id(s, presence);
+ rexmpp_xml_add_attr(presence, "from",
+ s->assigned_jid.full);
+ rexmpp_xml_t *nick =
rexmpp_xml_find_child(conference,
"urn:xmpp:bookmarks:1",
"nick");
- char *nick_str;
+ const char *nick_str;
if (nick != NULL) {
- nick_str = xmlNodeGetContent(nick);
+ nick_str = rexmpp_xml_text_child(nick);
} else {
- nick_str = strdup(s->initial_jid.local);
+ nick_str = s->initial_jid.local;
}
char *jid = malloc(strlen(item_id) + strlen(nick_str) + 2);
sprintf(jid, "%s/%s", item_id, nick_str);
- free(nick_str);
- xmlNewProp(presence, "to", jid);
+ rexmpp_xml_add_attr(presence, "to", jid);
free(jid);
- xmlNodePtr x = xmlNewNode(NULL, "x");
- xmlNewNs(x, "http://jabber.org/protocol/muc", NULL);
- xmlAddChild(presence, x);
+ rexmpp_xml_t *x =
+ rexmpp_xml_new_elem("x",
+ "http://jabber.org/protocol/muc");
+ rexmpp_xml_add_child(presence, x);
rexmpp_send(s, presence);
}
- free(item_id);
- free(autojoin);
}
}
- free(node);
}
}
}
@@ -2264,23 +2105,21 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
int sasl_err;
if (rexmpp_xml_match(elem, "urn:ietf:params:xml:ns:xmpp-sasl",
"challenge")) {
- char *challenge = xmlNodeGetContent(elem);
+ const char *challenge = rexmpp_xml_text_child(elem);
sasl_err = rexmpp_sasl_step64 (s, challenge, (char**)&sasl_buf);
- free(challenge);
if (sasl_err) {
s->sasl_state = REXMPP_SASL_ERROR;
return REXMPP_E_SASL;
}
- xmlNodePtr response = xmlNewNode(NULL, "response");
- xmlNewNs(response, "urn:ietf:params:xml:ns:xmpp-sasl", NULL);
- xmlNodeAddContent(response, sasl_buf);
+ rexmpp_xml_t *response =
+ rexmpp_xml_new_elem("response", "urn:ietf:params:xml:ns:xmpp-sasl");
+ rexmpp_xml_add_text(response, sasl_buf);
free(sasl_buf);
- return rexmpp_send(s, response);
+ rexmpp_send(s, response);
} else if (rexmpp_xml_match(elem, "urn:ietf:params:xml:ns:xmpp-sasl",
"success")) {
- char *success = xmlNodeGetContent(elem);
+ const char *success = rexmpp_xml_text_child(elem);
sasl_err = rexmpp_sasl_step64 (s, success, (char**)&sasl_buf);
- free(success);
free(sasl_buf);
if (! sasl_err) {
rexmpp_log(s, LOG_DEBUG, "SASL success");
@@ -2303,20 +2142,19 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
if (s->stream_state == REXMPP_STREAM_SM_FULL) {
if (rexmpp_xml_match(elem, "urn:xmpp:sm:3", "enabled")) {
s->sm_state = REXMPP_SM_ACTIVE;
- char *resume = xmlGetProp(elem, "resume");
+ const char *resume = rexmpp_xml_find_attr_val(elem, "resume");
if (resume != NULL) {
if (s->stream_id != NULL) {
free(s->stream_id);
}
- s->stream_id = xmlGetProp(elem, "id");
- xmlFree(resume);
+ s->stream_id = strdup(rexmpp_xml_find_attr_val(elem, "id"));
}
rexmpp_stream_is_ready(s);
} else if (rexmpp_xml_match(elem, "urn:xmpp:sm:3", "failed")) {
s->stream_state = REXMPP_STREAM_SM_ACKS;
s->sm_state = REXMPP_SM_NEGOTIATION;
- xmlNodePtr sm_enable = xmlNewNode(NULL, "enable");
- xmlNewNs(sm_enable, "urn:xmpp:sm:3", NULL);
+ rexmpp_xml_t *sm_enable =
+ rexmpp_xml_new_elem("enable", "urn:xmpp:sm:3");
rexmpp_send(s, sm_enable);
}
} else if (s->stream_state == REXMPP_STREAM_SM_ACKS) {
@@ -2328,8 +2166,8 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
}
} else if (rexmpp_xml_match(elem, "urn:xmpp:sm:3", "failed")) {
s->sm_state = REXMPP_SM_INACTIVE;
- xmlNodePtr sm_enable = xmlNewNode(NULL, "enable");
- xmlNewNs(sm_enable, "urn:xmpp:sm:3", NULL);
+ rexmpp_xml_t *sm_enable =
+ rexmpp_xml_new_elem("enable", "urn:xmpp:sm:3");
rexmpp_send(s, sm_enable);
}
rexmpp_stream_is_ready(s);
@@ -2350,7 +2188,7 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) {
s->active_iq = next;
rexmpp_iq_finish(s, iq, 0, NULL);
}
- xmlNodePtr child =
+ rexmpp_xml_t *child =
rexmpp_xml_find_child(s->stream_features,
"urn:ietf:params:xml:ns:xmpp-bind",
"bind");
@@ -2475,12 +2313,16 @@ rexmpp_err_t rexmpp_close (rexmpp_t *s) {
}
rexmpp_err_t rexmpp_stop (rexmpp_t *s) {
- s->stream_state = REXMPP_STREAM_CLOSE_REQUESTED;
if (s->stream_state == REXMPP_STREAM_READY) {
- xmlNodePtr presence = rexmpp_xml_add_id(s, xmlNewNode(NULL, "presence"));
- xmlNewProp(presence, "type", "unavailable");
+ rexmpp_xml_t *presence =
+ rexmpp_xml_new_elem("presence", "jabber:client");
+ rexmpp_xml_add_id(s, presence);
+ rexmpp_xml_add_attr(presence, "type", "unavailable");
rexmpp_send(s, presence);
}
+
+ s->stream_state = REXMPP_STREAM_CLOSE_REQUESTED;
+
if (s->sm_state == REXMPP_SM_ACTIVE) {
int ret = rexmpp_sm_ack(s);
if (ret > REXMPP_E_AGAIN) {
@@ -2642,8 +2484,8 @@ rexmpp_err_t rexmpp_run (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
s->last_network_activity + s->ping_delay <= time(NULL)) {
if (s->ping_requested == 0) {
s->ping_requested = 1;
- xmlNodePtr ping_cmd = xmlNewNode(NULL, "ping");
- xmlNewNs(ping_cmd, "urn:xmpp:ping", NULL);
+ rexmpp_xml_t *ping_cmd =
+ rexmpp_xml_new_elem("ping", "urn:xmpp:ping");
rexmpp_iq_new(s, "get", s->initial_jid.domain,
ping_cmd, rexmpp_pong, NULL);
} else {