summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README4
-rw-r--r--emacs/xml_interface.c159
-rw-r--r--examples/basic.c13
-rw-r--r--src/Makefile.am5
-rw-r--r--src/rexmpp.c790
-rw-r--r--src/rexmpp.h112
-rw-r--r--src/rexmpp_console.c412
-rw-r--r--src/rexmpp_console.h4
-rw-r--r--src/rexmpp_http_upload.c49
-rw-r--r--src/rexmpp_jingle.c575
-rw-r--r--src/rexmpp_jingle.h8
-rw-r--r--src/rexmpp_openpgp.c262
-rw-r--r--src/rexmpp_openpgp.h10
-rw-r--r--src/rexmpp_pubsub.c51
-rw-r--r--src/rexmpp_pubsub.h4
-rw-r--r--src/rexmpp_roster.c76
-rw-r--r--src/rexmpp_roster.h14
-rw-r--r--src/rexmpp_xml.c592
-rw-r--r--src/rexmpp_xml.h232
19 files changed, 1941 insertions, 1431 deletions
diff --git a/README b/README
index 9fdc4f6..e980262 100644
--- a/README
+++ b/README
@@ -53,8 +53,8 @@ A rough roadmap:
[.] Texinfo manual.
[.] Proper JID handling (RFC 7622).
[+] Abstraction of the used XML, SASL, TLS, and DNS libraries, and
- optional usage of alternative ones. Though left libxml2 for now:
- could reuse existing libxml2 bindings that way.
+ optional usage of alternative ones. Though only supporting libxml2
+ for XML parsing and printing for now.
[.] Automated testing.
[.] Alternative module implementations in Rust.
diff --git a/emacs/xml_interface.c b/emacs/xml_interface.c
index 2f4ebba..3dabf96 100644
--- a/emacs/xml_interface.c
+++ b/emacs/xml_interface.c
@@ -20,20 +20,22 @@ and EOF ones, to simplify reading with libxml2.
#include <syslog.h>
#include <gnutls/gnutls.h>
#include <rexmpp.h>
+#include <rexmpp_xml.h>
#include <rexmpp_openpgp.h>
+#include <rexmpp_http_upload.h>
-void print_xml (xmlNodePtr node) {
+void print_xml (rexmpp_xml_t *node) {
char *s = rexmpp_xml_serialize(node);
printf("%s%c\n", s, '\0');
free(s);
}
-xmlNodePtr read_xml () {
- xmlNodePtr elem = NULL;
+rexmpp_xml_t *read_xml () {
+ rexmpp_xml_t *elem = NULL;
xmlDocPtr doc = xmlReadFd(STDIN_FILENO, "", "utf-8", 0);
if (doc != NULL) {
- elem = xmlCopyNode(xmlDocGetRootElement(doc), 1);
+ elem = rexmpp_xml_from_libxml2(xmlDocGetRootElement(doc));
xmlFreeDoc(doc);
return elem;
}
@@ -41,70 +43,72 @@ xmlNodePtr read_xml () {
}
-char *request (rexmpp_t *s, xmlNodePtr payload)
+char *request (rexmpp_t *s, rexmpp_xml_t *payload)
{
- xmlNodePtr req = rexmpp_xml_add_id(s, xmlNewNode(NULL, "request"));
- xmlAddChild(req, payload);
+ rexmpp_xml_t *req = rexmpp_xml_new_elem("request", NULL);
+ rexmpp_xml_add_id(s, req);
+ rexmpp_xml_add_child(req, payload);
print_xml(req);
- char *id = xmlGetProp(req, "id");
- xmlFreeNode(req);
+ char *id = strdup(rexmpp_xml_find_attr_val(req, "id"));
+ rexmpp_xml_free(req);
return id;
}
-xmlNodePtr read_response (rexmpp_t *s, const char *id) {
- xmlNodePtr elem = read_xml();
+void req_process (rexmpp_t *s,
+ rexmpp_xml_t *elem);
+
+rexmpp_xml_t *read_response (rexmpp_t *s, const char *id) {
+ rexmpp_xml_t *elem = read_xml();
if (elem != NULL) {
if (rexmpp_xml_match(elem, NULL, "response")) {
- char *resp_id = xmlGetProp(elem, "id");
+ const char *resp_id = rexmpp_xml_find_attr_val(elem, "id");
if (resp_id != NULL) {
- int matches = (strcmp(resp_id, id) == 0);
- free(resp_id);
- if (matches) {
+ if (strcmp(resp_id, id) == 0) {
return elem;
} else {
/* Just fail for now, to avoid deadlocks. Though this
shouldn't happen. */
- xmlFreeNode(elem);
+ rexmpp_xml_free(elem);
rexmpp_log(s, LOG_ERR, "Unexpected response ID received.");
return NULL;
}
}
}
req_process(s, elem);
- xmlFreeNode(elem);
+ rexmpp_xml_free(elem);
}
return read_response(s, id);
}
-xmlNodePtr req_block (rexmpp_t *s, xmlNodePtr req) {
+rexmpp_xml_t *req_block (rexmpp_t *s, rexmpp_xml_t *req) {
char *id = request(s, req);
- xmlNodePtr resp = read_response(s, id);
+ rexmpp_xml_t *resp = read_response(s, id);
free(id);
return resp;
}
void respond_xml (rexmpp_t *s,
const char *id,
- xmlNodePtr payload) {
- xmlNodePtr response = xmlNewNode(NULL, "response");
- xmlNewProp(response, "id", id);
+ rexmpp_xml_t *payload) {
+ rexmpp_xml_t *response = rexmpp_xml_new_elem("response", NULL);
+ rexmpp_xml_add_attr(response, "id", id);
if (payload != NULL) {
- xmlAddChild(response, payload);
+ rexmpp_xml_add_child(response, payload);
}
print_xml(response);
- xmlFreeNode(response);
+ rexmpp_xml_free(response);
}
void respond_text (rexmpp_t *s,
const char *id,
const char *buf) {
- xmlNodePtr response = xmlNewNode(NULL, "response");
- xmlNewProp(response, "id", id);
+ rexmpp_xml_t *response = rexmpp_xml_new_elem("response", NULL);
+ rexmpp_xml_add_attr(response, "id", id);
if (buf != NULL) {
- xmlNodeAddContent(response, buf);
+ rexmpp_xml_add_text(response, buf);
}
print_xml(response);
- xmlFreeNode(response);
+ rexmpp_xml_free(response);
}
void on_http_upload (rexmpp_t *s, void *cb_data, const char *url) {
@@ -114,84 +118,83 @@ void on_http_upload (rexmpp_t *s, void *cb_data, const char *url) {
}
void req_process (rexmpp_t *s,
- xmlNodePtr elem)
+ rexmpp_xml_t *elem)
{
- char *id = xmlGetProp(elem, "id");
+ const char *id = rexmpp_xml_find_attr_val(elem, "id");
if (id == NULL) {
return;
}
rexmpp_err_t err;
char buf[64];
- xmlNodePtr child = xmlFirstElementChild(elem);
+ rexmpp_xml_t *child = rexmpp_xml_first_elem_child(elem);
if (rexmpp_xml_match(child, NULL, "stop")) {
snprintf(buf, 64, "%d", rexmpp_stop(s));
respond_text(s, id, buf);
} else if (rexmpp_xml_match(child, NULL, "console")) {
- char *in = xmlNodeGetContent(child);
+ char *in = strdup(rexmpp_xml_text_child(child));
rexmpp_console_feed(s, in, strlen(in));
free(in);
respond_text(s, id, NULL);
} else if (rexmpp_xml_match(child, NULL, "send")) {
- if (xmlFirstElementChild(child)) {
- xmlNodePtr stanza = xmlCopyNode(xmlFirstElementChild(child), 1);
+ if (rexmpp_xml_first_elem_child(child)) {
+ rexmpp_xml_t *stanza =
+ rexmpp_xml_clone(rexmpp_xml_first_elem_child(child));
snprintf(buf, 64, "%d", rexmpp_send(s, stanza));
respond_text(s, id, buf);
}
} else if (rexmpp_xml_match(child, NULL, "openpgp-decrypt-message")) {
int valid;
- xmlNodePtr plaintext =
- rexmpp_openpgp_decrypt_verify_message(s, xmlFirstElementChild(child),
+ rexmpp_xml_t *plaintext =
+ rexmpp_openpgp_decrypt_verify_message(s, rexmpp_xml_first_elem_child(child),
&valid);
/* todo: wrap into another element, with the 'valid' attribute */
respond_xml(s, id, plaintext);
} else if (rexmpp_xml_match(child, NULL, "openpgp-payload")) {
enum rexmpp_ox_mode mode = REXMPP_OX_CRYPT;
- char *mode_str = xmlGetProp(child, "mode");
+ const char *mode_str = rexmpp_xml_find_attr_val(child, "mode");
if (strcmp(mode_str, "sign") == 0) {
mode = REXMPP_OX_SIGN;
} else if (strcmp(mode_str, "signcrypt") == 0) {
mode = REXMPP_OX_SIGNCRYPT;
}
- free(mode_str);
- xmlNodePtr payload_xml =
- xmlFirstElementChild(rexmpp_xml_find_child(child, NULL, "payload"));
+ rexmpp_xml_t *payload_xml =
+ rexmpp_xml_first_elem_child(rexmpp_xml_find_child(child, NULL, "payload"));
- char **recipients[16];
+ char *recipients[16];
int recipients_num = 0;
- xmlNodePtr plchild;
- for (plchild = xmlFirstElementChild(child);
+ rexmpp_xml_t *plchild;
+ for (plchild = rexmpp_xml_first_elem_child(child);
plchild != NULL && recipients_num < 15;
plchild = plchild->next) {
if (rexmpp_xml_match(plchild, NULL, "to")) {
- recipients[recipients_num] = xmlNodeGetContent(plchild);
+ recipients[recipients_num] = strdup(rexmpp_xml_text_child(plchild));
recipients_num++;
}
}
recipients[recipients_num] = NULL;
char *payload_str =
- rexmpp_openpgp_payload(s, xmlCopyNode(payload_xml, 1), recipients, NULL, mode);
+ rexmpp_openpgp_payload(s, rexmpp_xml_clone(payload_xml),
+ (const char **)recipients, NULL, mode);
for (recipients_num = 0; recipients[recipients_num] != NULL; recipients_num++) {
free(recipients[recipients_num]);
}
respond_text(s, id, payload_str);
free(payload_str);
} else if (rexmpp_xml_match(child, NULL, "get-name")) {
- char *jid = xmlNodeGetContent(child);
+ const char *jid = rexmpp_xml_text_child(child);
if (jid != NULL) {
char *name = rexmpp_get_name(s, jid);
if (name != NULL) {
respond_text(s, id, name);
free(name);
}
- free(jid);
}
} else if (rexmpp_xml_match(child, NULL, "http-upload")) {
- char *in = xmlNodeGetContent(child);
+ char *in = strdup(rexmpp_xml_text_child(child));
rexmpp_http_upload_path(s, NULL, in, NULL, on_http_upload, strdup(id));
free(in);
}
- free(id);
return;
}
@@ -210,22 +213,23 @@ void my_logger (rexmpp_t *s, int priority, const char *fmt, va_list args) {
case LOG_INFO: priority_str = "info"; break;
case LOG_DEBUG: priority_str = "debug"; break;
}
- xmlNodePtr node = xmlNewNode(NULL, "log");
- xmlNewProp(node, "priority", priority_str);
- xmlNodeAddContent(node, buf);
+ rexmpp_xml_t *node = rexmpp_xml_new_elem("log", NULL);
+ rexmpp_xml_add_attr(node, "priority", priority_str);
+ rexmpp_xml_add_text(node, buf);
free(buf);
print_xml(node);
- xmlFreeNode(node);
+ rexmpp_xml_free(node);
}
-void my_console_print_cb (rexmpp_t *s, const char *fmt, va_list args) {
+int my_console_print_cb (rexmpp_t *s, const char *fmt, va_list args) {
char *buf = malloc(1024 * 20);
vsnprintf(buf, 1024 * 20, fmt, args);
- xmlNodePtr node = xmlNewNode(NULL, "console");
- xmlNodeAddContent(node, buf);
+ rexmpp_xml_t *node = rexmpp_xml_new_elem("console", NULL);
+ rexmpp_xml_add_text(node, buf);
free(buf);
print_xml(node);
- xmlFreeNode(node);
+ rexmpp_xml_free(node);
+ return 0;
}
int my_sasl_property_cb (rexmpp_t *s, rexmpp_sasl_property prop) {
@@ -239,53 +243,50 @@ int my_sasl_property_cb (rexmpp_t *s, rexmpp_sasl_property prop) {
case REXMPP_SASL_PROP_AUTHID: prop_str = "authid"; break;
default: return -1;
}
- xmlNodePtr req = xmlNewNode(NULL, "sasl");
- xmlNewProp(req, "property", prop_str);
- xmlNodePtr rep = req_block(s, req);
+ rexmpp_xml_t *req = rexmpp_xml_new_elem("sasl", NULL);
+ rexmpp_xml_add_attr(req, "property", prop_str);
+ rexmpp_xml_t *rep = req_block(s, req);
if (rep == NULL) {
return -1;
}
- char *val = xmlNodeGetContent(rep);
- xmlFreeNode(rep);
+ const char *val = rexmpp_xml_text_child(rep);
if (val == NULL) {
return -1;
}
rexmpp_sasl_property_set (s, prop, val);
- free(val);
+ rexmpp_xml_free(rep);
return GSASL_OK;
}
-int my_xml_in_cb (rexmpp_t *s, xmlNodePtr node) {
- xmlNodePtr req = xmlNewNode(NULL, "xml-in");
- xmlAddChild(req, xmlCopyNode(node, 1));
- xmlNodePtr rep = req_block(s, req);
+int my_xml_in_cb (rexmpp_t *s, rexmpp_xml_t *node) {
+ rexmpp_xml_t *req = rexmpp_xml_new_elem("xml-in", NULL);
+ rexmpp_xml_add_child(req, rexmpp_xml_clone(node));
+ rexmpp_xml_t *rep = req_block(s, req);
if (rep == NULL) {
return 0;
}
- char *val = xmlNodeGetContent(rep);
- xmlFreeNode(rep);
+ const char *val = rexmpp_xml_text_child(rep);
if (val == NULL) {
return 0;
}
int n = atoi(val);
- free(val);
+ rexmpp_xml_free(rep);
return n;
}
-int my_xml_out_cb (rexmpp_t *s, xmlNodePtr node) {
- xmlNodePtr req = xmlNewNode(NULL, "xml-out");
- xmlAddChild(req, xmlCopyNode(node, 1));
- xmlNodePtr rep = req_block(s, req);
+int my_xml_out_cb (rexmpp_t *s, rexmpp_xml_t *node) {
+ rexmpp_xml_t *req = rexmpp_xml_new_elem("xml-out", NULL);
+ rexmpp_xml_add_child(req, rexmpp_xml_clone(node));
+ rexmpp_xml_t *rep = req_block(s, req);
if (rep == NULL) {
return 0;
}
- char *val = xmlNodeGetContent(rep);
- xmlFreeNode(rep);
+ const char *val = rexmpp_xml_text_child(rep);
if (val == NULL) {
return 0;
}
int n = atoi(val);
- free(val);
+ rexmpp_xml_free(rep);
return n;
}
@@ -338,10 +339,10 @@ int main (int argc, char **argv) {
do {
/* Check if we have some user input. */
if (n > 0 && FD_ISSET(STDIN_FILENO, &read_fds)) {
- xmlNodePtr elem = read_xml();
+ rexmpp_xml_t *elem = read_xml();
if (elem != NULL) {
req_process(&s, elem);
- xmlFreeNode(elem);
+ rexmpp_xml_free(elem);
}
}
diff --git a/examples/basic.c b/examples/basic.c
index 982106a..66c54f6 100644
--- a/examples/basic.c
+++ b/examples/basic.c
@@ -13,6 +13,7 @@
#include <gsasl.h>
#include <time.h>
#include <rexmpp.h>
+#include <rexmpp_xml.h>
#include <rexmpp_sasl.h>
int log_level = 8;
@@ -66,7 +67,7 @@ int my_sasl_property_cb (rexmpp_t *s, rexmpp_sasl_property prop) {
}
/* An XML in callback, printing what was received. */
-int my_xml_in_cb (rexmpp_t *s, xmlNodePtr node) {
+int my_xml_in_cb (rexmpp_t *s, rexmpp_xml_t *node) {
char *xml_buf = rexmpp_xml_serialize(node);
printf("recv: %s\n", xml_buf);
free(xml_buf);
@@ -74,7 +75,7 @@ int my_xml_in_cb (rexmpp_t *s, xmlNodePtr node) {
}
/* An XML out callback, printing what is about to be sent. */
-int my_xml_out_cb (rexmpp_t *s, xmlNodePtr node) {
+int my_xml_out_cb (rexmpp_t *s, rexmpp_xml_t *node) {
char *xml_buf = rexmpp_xml_serialize(node);
printf("send: %s\n", xml_buf);
free(xml_buf);
@@ -178,9 +179,11 @@ int main (int argc, char **argv) {
/* Raw XML input. */
xmlDocPtr doc = xmlReadMemory(input, input_len, "", "utf-8", 0);
if (doc != NULL) {
- xmlNodePtr node = xmlDocGetRootElement(doc);
- if (node != NULL) {
- xmlUnlinkNode(node);
+ xmlNodePtr node_libxml2 = xmlDocGetRootElement(doc);
+ if (node_libxml2 != NULL) {
+ xmlUnlinkNode(node_libxml2);
+ rexmpp_xml_t *node = rexmpp_xml_from_libxml2(node_libxml2);
+ xmlFreeNode(node_libxml2);
rexmpp_send(&s, node);
} else {
puts("No root node");
diff --git a/src/Makefile.am b/src/Makefile.am
index de0a68f..0955d81 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,12 +21,13 @@ librexmpp_la_SOURCES = rexmpp_roster.h rexmpp_roster.c \
rexmpp_http_upload.h rexmpp_http_upload.c \
rexmpp_jingle.h rexmpp_jingle.c \
rexmpp_base64.h rexmpp_base64.c \
- rexmpp_sasl.h rexmpp_sasl.c
+ rexmpp_sasl.h rexmpp_sasl.c \
+ rexmpp_xml.h rexmpp_xml.c
include_HEADERS = config.h rexmpp_roster.h rexmpp_tcp.h rexmpp_socks.h rexmpp.h \
rexmpp_dns.h rexmpp_tls.h rexmpp_jid.h rexmpp_openpgp.h rexmpp_console.h \
rexmpp_pubsub.h rexmpp_http_upload.h rexmpp_jingle.h rexmpp_base64.h \
- rexmpp_sasl.h
+ rexmpp_sasl.h rexmpp_xml.h
librexmpp_la_CFLAGS = $(AM_CFLAGS) $(LIBXML_CFLAGS) \
$(GNUTLS_CFLAGS) $(LIBDANE_CFLAGS) $(OPENSSL_CFLAGS) \
$(GSASL_CFLAGS) $(UNBOUND_CFLAGS) $(CARES_CFLAGS) $(GPGME_CFLAGS) \
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 {
diff --git a/src/rexmpp.h b/src/rexmpp.h
index 13b6c08..94f2df2 100644
--- a/src/rexmpp.h
+++ b/src/rexmpp.h
@@ -187,6 +187,7 @@ enum tls_pol {
typedef enum rexmpp_err rexmpp_err_t;
+#include "rexmpp_xml.h"
#include "rexmpp_tcp.h"
#include "rexmpp_socks.h"
#include "rexmpp_dns.h"
@@ -207,8 +208,8 @@ typedef enum rexmpp_err rexmpp_err_t;
*/
typedef void (*rexmpp_iq_callback_t) (rexmpp_t *s,
void *cb_data,
- xmlNodePtr request,
- xmlNodePtr response,
+ rexmpp_xml_t *request,
+ rexmpp_xml_t *response,
int success);
typedef struct rexmpp_iq rexmpp_iq_t;
@@ -217,7 +218,7 @@ typedef struct rexmpp_iq rexmpp_iq_t;
struct rexmpp_iq
{
/** @brief The sent request. */
- xmlNodePtr request;
+ rexmpp_xml_t *request;
/** @brief A callback to call on reply. */
rexmpp_iq_callback_t cb;
/** @brief User-supplied data, to pass to a callback function. */
@@ -228,9 +229,9 @@ struct rexmpp_iq
typedef void (*log_function_t) (rexmpp_t *s, int priority, const char *format, va_list args);
typedef int (*sasl_property_cb_t) (rexmpp_t *s, rexmpp_sasl_property prop);
-typedef int (*xml_in_cb_t) (rexmpp_t *s, xmlNodePtr node);
-typedef int (*xml_out_cb_t) (rexmpp_t *s, xmlNodePtr node);
-typedef void (*roster_modify_cb_t) (rexmpp_t *s, xmlNodePtr item);
+typedef int (*xml_in_cb_t) (rexmpp_t *s, rexmpp_xml_t *node);
+typedef int (*xml_out_cb_t) (rexmpp_t *s, rexmpp_xml_t *node);
+typedef void (*roster_modify_cb_t) (rexmpp_t *s, rexmpp_xml_t *item);
typedef int (*console_print_cb_t) (rexmpp_t *s, const char *format, va_list args);
/** @brief Complete connection state */
@@ -298,23 +299,23 @@ struct rexmpp
/* Stream-related state. */
struct rexmpp_jid assigned_jid;
- xmlNodePtr stream_features;
- xmlNodePtr roster_items;
+ rexmpp_xml_t *stream_features;
+ rexmpp_xml_t *roster_items;
char *roster_ver;
- xmlNodePtr roster_presence;
- xmlNodePtr roster_events;
+ rexmpp_xml_t *roster_presence;
+ rexmpp_xml_t *roster_events;
/* Other dynamic data. */
- xmlNodePtr disco_info;
+ rexmpp_xml_t *disco_info;
/* Includes Jingle RTP session candidates; rexmpp prioritizes the
ones listed earlier on incoming calls. */
- xmlNodePtr jingle_rtp_description;
+ rexmpp_xml_t *jingle_rtp_description;
/* IQs we're waiting for responses to. */
rexmpp_iq_t *active_iq;
/* Cached IQ requests and responses. */
- xmlNodePtr iq_cache;
+ rexmpp_xml_t *iq_cache;
/* Jingle context. */
rexmpp_jingle_ctx_t jingle;
@@ -323,7 +324,7 @@ struct rexmpp
unsigned int reconnect_number;
time_t reconnect_seconds;
struct timespec next_reconnect_time;
- xmlNodePtr stanza_queue;
+ rexmpp_xml_t *stanza_queue;
uint32_t stanzas_out_count;
uint32_t stanzas_out_acknowledged;
uint32_t stanzas_in_count;
@@ -365,7 +366,7 @@ struct rexmpp
ssize_t send_buffer_sent;
/* A queue of XML elements to send. */
- xmlNodePtr send_queue;
+ rexmpp_xml_t *send_queue;
/* XML parser context, and current element pointer for building
XML nodes with a SAX2 parser interface. */
@@ -431,7 +432,7 @@ rexmpp_err_t rexmpp_stop (rexmpp_t *s);
@param[in] node An XML element to send. The library assumes
ownership of the element, so it must not be freed by the caller.
*/
-rexmpp_err_t rexmpp_send (rexmpp_t *s, xmlNodePtr node);
+rexmpp_err_t rexmpp_send (rexmpp_t *s, rexmpp_xml_t *node);
/**
@brief Prepare and send a new info/query request.
@@ -450,7 +451,7 @@ rexmpp_err_t rexmpp_send (rexmpp_t *s, xmlNodePtr node);
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);
@@ -462,7 +463,7 @@ rexmpp_err_t rexmpp_iq_new (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);
@@ -471,9 +472,9 @@ rexmpp_err_t rexmpp_cached_iq_new (rexmpp_t *s,
@brief Reply to an IQ.
*/
void rexmpp_iq_reply (rexmpp_t *s,
- xmlNodePtr req,
+ rexmpp_xml_t *req,
const char *type,
- xmlNodePtr payload);
+ rexmpp_xml_t *payload);
/**
@brief Determines the maximum time to wait before the next
@@ -502,35 +503,6 @@ struct timespec *rexmpp_timeout (rexmpp_t *s,
int rexmpp_fds (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds);
/**
- @brief Compose an 'error' element.
-*/
-xmlNodePtr rexmpp_xml_error (const char *type, const char *condition);
-
-/**
- @brief A helper function for XML parsing.
- @param[in] str A string to parse.
- @param[in] str_len String length.
- @returns Parsed XML, or NULL on failure.
-*/
-xmlNodePtr rexmpp_xml_parse (const char *str, int str_len);
-
-/**
- @brief A helper function for XML serialisation.
- @param[in] node An XML node.
- @returns A string (must be freed by the caller).
-*/
-char *rexmpp_xml_serialize (xmlNodePtr node);
-
-/**
- @brief Adds an "id" attribute to an XML stanza.
- @param[in,out] s ::rexmpp
- @param[in] node A pointer to an XML stanza.
- @returns The same pointer as on input, for more convenient
- composition.
-*/
-xmlNodePtr rexmpp_xml_add_id (rexmpp_t *s, xmlNodePtr node);
-
-/**
@brief The logging function.
@param[in] s ::rexmpp
@param[in] priority A syslog priority.
@@ -548,40 +520,6 @@ void rexmpp_log (rexmpp_t *s, int priority, const char *format, ...);
*/
char *rexmpp_get_name (rexmpp_t *s, const char *jid_str);
-/**
- @brief Compares two XML elements.
-*/
-int rexmpp_xml_eq (xmlNodePtr n1, xmlNodePtr n2);
-
-/**
- @brief Matches an XML node against a namespace and an element name.
- @param[in] node An XML node to match.
- @param[in] namespace An XML namespace. Can be NULL (matches
- anything), and it is assumed that the default namespace is
- "jabber:client" (so if it is "jabber:client" and an element doesn't
- have a namespace defined, this function counts that as a match).
- @param[in] name Element name. Can be NULL (matches anything).
- @returns 1 on a successful match, 0 otherwise.
-*/
-int rexmpp_xml_match (xmlNodePtr node,
- const char *namespace,
- const char *name);
-
-/**
- @brief Finds a child element of an XML node, which matches the
- given namespace and name.
- @param[in] node The node containing child nodes.
- @param[in] namespace The namespace to look for.
- @param[in] name The element name to look for.
- @returns A pointer to the first matching child node, or NULL if no
- matching child elements found.
-*/
-xmlNodePtr rexmpp_xml_find_child (xmlNodePtr node,
- const char *namespace,
- const char *name);
-
-xmlNodePtr rexmpp_xml_new_node (const char *name, const char *namespace);
-
char *rexmpp_gen_id (rexmpp_t *s);
/**
@@ -593,10 +531,10 @@ char *rexmpp_gen_id (rexmpp_t *s);
@returns A pointer to the message announcing an event, or NULL on
failure.
*/
-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);
void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len);
diff --git a/src/rexmpp_console.c b/src/rexmpp_console.c
index b863672..ce325aa 100644
--- a/src/rexmpp_console.c
+++ b/src/rexmpp_console.c
@@ -13,6 +13,7 @@
#include <string.h>
#include "rexmpp.h"
+#include "rexmpp_xml.h"
#include "rexmpp_openpgp.h"
#include "rexmpp_http_upload.h"
#include "rexmpp_jingle.h"
@@ -30,61 +31,60 @@ void rexmpp_console_printf (rexmpp_t *s, const char *format, ...)
}
}
-char *rexmpp_console_message_string (rexmpp_t *s, xmlNodePtr node) {
- char *ret = NULL;
- xmlNodePtr openpgp =
+const char *rexmpp_console_message_string (rexmpp_t *s, rexmpp_xml_t *node) {
+ const char *ret = NULL;
+ rexmpp_xml_t *openpgp =
rexmpp_xml_find_child(node, "urn:xmpp:openpgp:0", "openpgp");
if (openpgp != NULL) {
int valid;
- xmlNodePtr elem = rexmpp_openpgp_decrypt_verify_message(s, node, &valid);
+ rexmpp_xml_t *elem = rexmpp_openpgp_decrypt_verify_message(s, node, &valid);
if (! valid) {
rexmpp_console_printf(s, "An invalid OpenPGP message!\n");
}
if (elem != NULL) {
- xmlNodePtr payload =
+ rexmpp_xml_t *payload =
rexmpp_xml_find_child(elem, "urn:xmpp:openpgp:0", "payload");
if (payload != NULL) {
- xmlNodePtr pl_body =
+ rexmpp_xml_t *pl_body =
rexmpp_xml_find_child(payload, "jabber:client", "body");
if (pl_body != NULL) {
- ret = xmlNodeGetContent(pl_body);
+ ret = rexmpp_xml_text_child(pl_body);
}
}
- xmlFreeNode(elem);
+ rexmpp_xml_free(elem);
}
}
if (ret == NULL) {
- xmlNodePtr body = rexmpp_xml_find_child(node, "jabber:client", "body");
- ret = xmlNodeGetContent(body);
+ rexmpp_xml_t *body =
+ rexmpp_xml_find_child(node, "jabber:client", "body");
+ ret = rexmpp_xml_text_child(body);
}
return ret;
}
-void rexmpp_console_on_send (rexmpp_t *s, xmlNodePtr node) {
+void rexmpp_console_on_send (rexmpp_t *s, rexmpp_xml_t *node) {
if (rexmpp_xml_match(node, "jabber:client", "message")) {
- char *to = xmlGetProp(node, "to");
+ const char *to = rexmpp_xml_find_attr_val(node, "to");
if (to != NULL) {
/* "from" should be set for verification. */
- char *from = xmlGetProp(node, "from");
- xmlAttrPtr fromProp = NULL;
- if (from == NULL) {
- fromProp = xmlNewProp(node, "from", to);
+ int added_from = 0;
+ if (rexmpp_xml_find_attr_val(node, "from") == NULL) {
+ rexmpp_xml_add_attr(node, "from", to);
+ added_from = 1;
}
- char *str = rexmpp_console_message_string(s, node);
- if (fromProp != NULL) {
- xmlRemoveProp(fromProp);
+ const char *str = rexmpp_console_message_string(s, node);
+ if (added_from) {
+ rexmpp_xml_remove_attr(node, "from");
}
if (str != NULL) {
rexmpp_console_printf(s, "You tell %s: %s\n", to, str);
- free(str);
}
- free(to);
}
}
if (rexmpp_xml_match(node, "jabber:client", "presence")) {
- char *presence_type = xmlGetProp(node, "type");
- char *presence_to = xmlGetProp(node, "to");
+ const char *presence_type = rexmpp_xml_find_attr_val(node, "type");
+ const char *presence_to = rexmpp_xml_find_attr_val(node, "to");
if (presence_to == NULL) {
rexmpp_console_printf(s, "Becoming %s\n",
(presence_type == NULL) ?
@@ -106,72 +106,58 @@ void rexmpp_console_on_send (rexmpp_t *s, xmlNodePtr node) {
"Denying %s's presence subscription request.\n",
presence_to);
}
- free(presence_to);
- }
- if (presence_type != NULL) {
- free(presence_type);
}
}
}
-void rexmpp_console_on_recv (rexmpp_t *s, xmlNodePtr node) {
+void rexmpp_console_on_recv (rexmpp_t *s, rexmpp_xml_t *node) {
if (rexmpp_xml_match(node, "jabber:client", "message")) {
- xmlNodePtr sent = rexmpp_xml_find_child(node, "urn:xmpp:carbons:2", "sent");
+ rexmpp_xml_t *sent = rexmpp_xml_find_child(node, "urn:xmpp:carbons:2", "sent");
if (sent != NULL) {
- xmlNodePtr fwd =
+ rexmpp_xml_t *fwd =
rexmpp_xml_find_child(sent, "urn:xmpp:forward:0", "forwarded");
if (fwd != NULL) {
- xmlNodePtr msg =
+ rexmpp_xml_t *msg =
rexmpp_xml_find_child(fwd, "jabber:client", "message");
if (msg != NULL) {
- char *to = xmlGetProp(msg, "to");
- char *str = rexmpp_console_message_string(s, msg);
+ const char *to = rexmpp_xml_find_attr_val(msg, "to");
+ const char *str = rexmpp_console_message_string(s, msg);
if (str != NULL) {
rexmpp_console_printf(s, "You tell %s: %s\n", to, str);
- free(str);
- }
- if (to != NULL) {
- free(to);
}
}
}
}
- xmlNodePtr received =
+ rexmpp_xml_t *received =
rexmpp_xml_find_child(node, "urn:xmpp:carbons:2", "received");
if (received != NULL) {
- xmlNodePtr fwd =
+ rexmpp_xml_t *fwd =
rexmpp_xml_find_child(received, "urn:xmpp:forward:0", "forwarded");
if (fwd != NULL) {
- xmlNodePtr msg =
+ rexmpp_xml_t *msg =
rexmpp_xml_find_child(fwd, "jabber:client", "message");
if (msg != NULL) {
- char *from = xmlGetProp(msg, "from");
- char *str = rexmpp_console_message_string(s, msg);
+ const char *from = rexmpp_xml_find_attr_val(msg, "from");
+ const char *str = rexmpp_console_message_string(s, msg);
if (str != NULL) {
rexmpp_console_printf(s, "%s tells you: %s\n", from, str);
- free(str);
- }
- if (from != NULL) {
- free(from);
}
}
}
}
- char *from = xmlGetProp(node, "from");
+ const char *from = rexmpp_xml_find_attr_val(node, "from");
if (from != NULL) {
- char *str = rexmpp_console_message_string(s, node);
+ const char *str = rexmpp_console_message_string(s, node);
if (str != NULL) {
rexmpp_console_printf(s, "%s tells you: %s\n", from, str);
- free(str);
}
- free(from);
}
}
if (rexmpp_xml_match(node, "jabber:client", "presence")) {
- char *presence_type = xmlGetProp(node, "type");
- char *from = xmlGetProp(node, "from");
+ const char *presence_type = rexmpp_xml_find_attr_val(node, "type");
+ const char *from = rexmpp_xml_find_attr_val(node, "from");
if (presence_type != NULL && ! strcmp(presence_type, "subscribe")) {
rexmpp_console_printf(s, "%s requests a presence subscription\n", from);
} else if (presence_type != NULL && ! strcmp(presence_type, "subscribed")) {
@@ -183,74 +169,64 @@ void rexmpp_console_on_recv (rexmpp_t *s, xmlNodePtr node) {
(presence_type == NULL) ?
"available" :
presence_type);
- xmlNodePtr show = rexmpp_xml_find_child(node, "jabber:client", "show");
+ rexmpp_xml_t *show =
+ rexmpp_xml_find_child(node, "jabber:client", "show");
if (show != NULL) {
- char *show_str = xmlNodeGetContent(show);
- rexmpp_console_printf(s, " (%s)", show_str);
- free(show_str);
- show_str = NULL;
+ rexmpp_console_printf(s, " (%s)",
+ rexmpp_xml_text_child(show));
}
- xmlNodePtr status = rexmpp_xml_find_child(node, "jabber:client", "status");
+ rexmpp_xml_t *status =
+ rexmpp_xml_find_child(node, "jabber:client", "status");
if (status != NULL) {
- char *status_str = xmlNodeGetContent(status);
- rexmpp_console_printf(s, ": %s", status_str);
- free(status_str);
- status_str = NULL;
+ rexmpp_console_printf(s, ": %s",
+ rexmpp_xml_text_child(status));
}
rexmpp_console_printf(s, "\n");
}
- if (presence_type != NULL) {
- free(presence_type);
- }
- if (from != NULL) {
- free(from);
- }
}
}
void rexmpp_console_roster_deleted (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
(void)response;
- xmlNodePtr item =
+ rexmpp_xml_t *item =
rexmpp_xml_find_child(rexmpp_xml_find_child(req,
"jabber:iq:roster",
"query"),
"jabber:iq:roster", "item");
- char *jid = xmlGetProp(item, "jid");
+ const char *jid = rexmpp_xml_find_attr_val(item, "jid");
if (success) {
rexmpp_console_printf(s, "Deleted %s from the roster.\n", jid);
} else {
rexmpp_console_printf(s, "Failed to delete %s from the roster.\n", jid);
}
- free(jid);
}
void rexmpp_console_roster_added (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
(void)response;
- xmlNodePtr item =
+ rexmpp_xml_t *item =
rexmpp_xml_find_child(rexmpp_xml_find_child(req,
"jabber:iq:roster",
"query"),
"jabber:iq:roster", "item");
- char *jid = xmlGetProp(item, "jid");
+ const char *jid = rexmpp_xml_find_attr_val(item, "jid");
if (success) {
rexmpp_console_printf(s, "Added %s into the roster.\n", jid);
} else {
rexmpp_console_printf(s, "Failed to add %s into the roster.\n", jid);
}
- free(jid);
}
void rexmpp_console_on_run (rexmpp_t *s, rexmpp_err_t result) {
@@ -272,8 +248,8 @@ void rexmpp_console_on_upload (rexmpp_t *s, void *cb_data, const char *url) {
void rexmpp_console_disco_info (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
@@ -282,57 +258,44 @@ void rexmpp_console_disco_info (rexmpp_t *s,
rexmpp_console_printf(s, "Failed to discover info.\n");
return;
}
- xmlNodePtr query =
+ rexmpp_xml_t *query =
rexmpp_xml_find_child(response, "http://jabber.org/protocol/disco#info",
"query");
if (query == NULL) {
rexmpp_console_printf(s, "No disco#info query in response.\n");
return;
}
- char *from = xmlGetProp(response, "from");
+ const char *from = rexmpp_xml_find_attr_val(response, "from");
if (from == NULL) {
rexmpp_console_printf(s, "No 'from' property in response.\n");
return;
}
rexmpp_console_printf(s, "Discovered info for %s:\n", from);
- xmlNodePtr child = xmlFirstElementChild(query);
+ rexmpp_xml_t *child = rexmpp_xml_first_elem_child(query);
while (child != NULL) {
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");
rexmpp_console_printf(s, "- feature var %s\n", var);
- if (var != NULL) {
- free(var);
- }
} else if (rexmpp_xml_match(child, "http://jabber.org/protocol/disco#info",
"identity")) {
- char *category = xmlGetProp(child, "category");
- char *type = xmlGetProp(child, "type");
- char *name = xmlGetProp(child, "name");
+ const char *category = rexmpp_xml_find_attr_val(child, "category");
+ const char *type = rexmpp_xml_find_attr_val(child, "type");
+ const char *name = rexmpp_xml_find_attr_val(child, "name");
rexmpp_console_printf(s, "- identity name %s, type %s, category %s\n",
name, type, category);
- if (category != NULL) {
- free(category);
- }
- if (type != NULL) {
- free(type);
- }
- if (name != NULL) {
- free(name);
- }
} else {
rexmpp_console_printf(s, "Encountered an unknown disco#info element.\n");
}
- child = child->next;
+ child = rexmpp_xml_next_elem_sibling(child);
}
rexmpp_console_printf(s, "(end of discovered info for %s)\n", from);
- free(from);
}
void rexmpp_console_disco_items (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
@@ -341,49 +304,39 @@ void rexmpp_console_disco_items (rexmpp_t *s,
rexmpp_console_printf(s, "Failed to discover items.\n");
return;
}
- xmlNodePtr query =
+ rexmpp_xml_t *query =
rexmpp_xml_find_child(response, "http://jabber.org/protocol/disco#items",
"query");
if (query == NULL) {
rexmpp_console_printf(s, "No disco#items query in response.\n");
return;
}
- char *from = xmlGetProp(response, "from");
+ const char *from = rexmpp_xml_find_attr_val(response, "from");
if (from == NULL) {
rexmpp_console_printf(s, "No 'from' property in response.\n");
return;
}
rexmpp_console_printf(s, "Discovered items for %s:\n", from);
- xmlNodePtr child = xmlFirstElementChild(query);
+ rexmpp_xml_t *child = rexmpp_xml_first_elem_child(query);
while (child != NULL) {
if (rexmpp_xml_match(child, "http://jabber.org/protocol/disco#items",
"item")) {
- char *jid = xmlGetProp(child, "jid");
- char *name = xmlGetProp(child, "name");
- char *node = xmlGetProp(child, "node");
- rexmpp_console_printf(s, "- item jid %s, name %s, node %s\n", jid, name);
- if (jid != NULL) {
- free(jid);
- }
- if (name != NULL) {
- free(name);
- }
- if (node != NULL) {
- free(node);
- }
+ const char *jid = rexmpp_xml_find_attr_val(child, "jid");
+ const char *name = rexmpp_xml_find_attr_val(child, "name");
+ const char *node = rexmpp_xml_find_attr_val(child, "node");
+ rexmpp_console_printf(s, "- item jid %s, name %s, node %s\n", jid, name, node);
} else {
rexmpp_console_printf(s, "Encountered an unknown disco#items element.\n");
}
- child = child->next;
+ child = rexmpp_xml_next_elem_sibling(child);
}
rexmpp_console_printf(s, "(end of discovered items for %s)\n", from);
- free(from);
}
void rexmpp_console_pubsub_node_deleted (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
@@ -398,31 +351,29 @@ void rexmpp_console_pubsub_node_deleted (rexmpp_t *s,
void rexmpp_console_blocklist (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
(void)req;
if (success) {
- xmlNodePtr bl = rexmpp_xml_find_child(response, "urn:xmpp:blocking", "blocklist");
+ rexmpp_xml_t *bl =
+ rexmpp_xml_find_child(response, "urn:xmpp:blocking", "blocklist");
if (bl == NULL) {
rexmpp_console_printf(s, "No blocklist element in the response.\n");
return;
}
rexmpp_console_printf(s, "Block list:");
- xmlNodePtr child = xmlFirstElementChild(bl);
+ rexmpp_xml_t *child = rexmpp_xml_first_elem_child(bl);
while (child != NULL) {
if (rexmpp_xml_match(child, "urn:xmpp:blocking", "item")) {
- char *jid = xmlGetProp(child, "jid");
+ const char *jid = rexmpp_xml_find_attr_val(child, "jid");
rexmpp_console_printf(s, " %s", jid);
- if (jid != NULL) {
- free(jid);
- }
} else {
rexmpp_console_printf(s, "Encountered an unknown blocklist child element.\n");
}
- child = child->next;
+ child = rexmpp_xml_next_elem_sibling(child);
}
rexmpp_console_printf(s, "\n");
} else {
@@ -432,8 +383,8 @@ void rexmpp_console_blocklist (rexmpp_t *s,
void rexmpp_console_blocklist_blocked (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
@@ -448,8 +399,8 @@ void rexmpp_console_blocklist_blocked (rexmpp_t *s,
void rexmpp_console_blocklist_unblocked (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
@@ -466,7 +417,7 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
/* todo: buffering */
(void)str_len; /* Unused for now (todo). */
char *words_save_ptr;
- xmlNodePtr presence;
+ rexmpp_xml_t *presence;
char *word, *jid_str, *msg_text;
struct rexmpp_jid jid;
word = strtok_r(str, " ", &words_save_ptr);
@@ -536,11 +487,14 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
return;
}
msg_text = jid_str + strlen(jid_str) + 1;
- xmlNodePtr msg = rexmpp_xml_add_id(s, xmlNewNode(NULL, "message"));
- xmlNewNs(msg, "jabber:client", NULL);
- xmlNewProp(msg, "to", jid.full);
- xmlNewProp(msg, "type", "chat");
- xmlNewTextChild(msg, NULL, "body", msg_text);
+
+ rexmpp_xml_t *msg = rexmpp_xml_new_elem("message", "jabber:client");
+ rexmpp_xml_add_id(s, msg);
+ rexmpp_xml_add_attr(msg, "to", jid.full);
+ rexmpp_xml_add_attr(msg, "type", "chat");
+ rexmpp_xml_t *body = rexmpp_xml_new_elem("body", NULL);
+ rexmpp_xml_add_text(body, msg_text);
+ rexmpp_xml_add_child(msg, body);
rexmpp_send(s, msg);
}
@@ -552,9 +506,9 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
return;
}
msg_text = jid_str + strlen(jid_str) + 1;
- xmlNodePtr body = xmlNewNode(NULL, "body");
- xmlNewNs(body, "jabber:client", NULL);
- xmlNodeAddContent(body, msg_text);
+ rexmpp_xml_t *body =
+ rexmpp_xml_new_elem("body", "jabber:client");
+ rexmpp_xml_add_text(body, msg_text);
const char *rcpt[2];
rcpt[0] = jid.full;
rcpt[1] = NULL;
@@ -566,21 +520,20 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
} else if (strcmp(word, "crypt") == 0) {
b64 = rexmpp_openpgp_payload(s, body, rcpt, NULL, REXMPP_OX_CRYPT);
}
- xmlNodePtr openpgp = xmlNewNode(NULL, "openpgp");
- openpgp->ns = xmlNewNs(openpgp, "urn:xmpp:openpgp:0", NULL);
- xmlNodeAddContent(openpgp, b64);
+ rexmpp_xml_t *openpgp =
+ rexmpp_xml_new_elem("openpgp", "urn:xmpp:openpgp:0");
+ rexmpp_xml_add_text(openpgp, b64);
free(b64);
- xmlNodePtr msg = rexmpp_xml_add_id(s, xmlNewNode(NULL, "message"));
- xmlNewNs(msg, "jabber:client", NULL);
- xmlNewProp(msg, "to", jid.full);
- xmlNewProp(msg, "type", "chat");
- xmlAddChild(msg, openpgp);
+ rexmpp_xml_t *msg = rexmpp_xml_new_elem("message", "jabber:client");
+ rexmpp_xml_add_id(s, msg);
+ rexmpp_xml_add_attr(msg, "to", jid.full);
+ rexmpp_xml_add_attr(msg, "type", "chat");
+ rexmpp_xml_add_child(msg, openpgp);
- body = xmlNewNode(NULL, "body");
- xmlNewNs(body, "jabber:client", NULL);
- xmlNodeAddContent(body, "This is a secret message.");
- xmlAddChild(msg, body);
+ body = rexmpp_xml_new_elem("body", "jabber:client");
+ rexmpp_xml_add_text(body, "This is a secret message.");
+ rexmpp_xml_add_child(msg, body);
rexmpp_send(s, msg);
}
@@ -593,11 +546,14 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
return;
}
msg_text = jid_str + strlen(jid_str) + 1;
- xmlNodePtr msg = rexmpp_xml_add_id(s, xmlNewNode(NULL, "message"));
- xmlNewNs(msg, "jabber:client", NULL);
- xmlNewProp(msg, "to", jid.full);
- xmlNewProp(msg, "type", "groupchat");
- xmlNewTextChild(msg, NULL, "body", msg_text);
+
+ rexmpp_xml_t *msg = rexmpp_xml_new_elem("message", "jabber:client");
+ rexmpp_xml_add_id(s, msg);
+ rexmpp_xml_add_attr(msg, "to", jid.full);
+ rexmpp_xml_add_attr(msg, "type", "groupchat");
+ rexmpp_xml_t *body = rexmpp_xml_new_elem("body", NULL);
+ rexmpp_xml_add_text(body, msg_text);
+ rexmpp_xml_add_child(msg, body);
rexmpp_send(s, msg);
}
if (! strcmp(word, "join")) {
@@ -615,12 +571,13 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
char *full_jid = malloc(strlen(jid.bare) + strlen(word) + 2);
snprintf(full_jid, strlen(jid_str) + strlen(word) + 2, "%s/%s",
jid.bare, word);
- presence = rexmpp_xml_add_id(s, xmlNewNode(NULL, "presence"));
- xmlNewProp(presence, "from", s->assigned_jid.full);
- xmlNewProp(presence, "to", full_jid);
- xmlNodePtr x = xmlNewNode(NULL, "x");
- xmlNewNs(x, "http://jabber.org/protocol/muc", NULL);
- xmlAddChild(presence, x);
+ 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_add_attr(presence, "to", full_jid);
+ 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(full_jid);
}
@@ -639,10 +596,11 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
char *full_jid = malloc(strlen(jid.bare) + strlen(word) + 2);
snprintf(full_jid, strlen(jid_str) + strlen(word) + 2, "%s/%s",
jid.bare, word);
- presence = rexmpp_xml_add_id(s, xmlNewNode(NULL, "presence"));
- xmlNewProp(presence, "from", s->assigned_jid.full);
- xmlNewProp(presence, "to", full_jid);
- xmlNewProp(presence, "type", "unavailable");
+ 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_add_attr(presence, "to", full_jid);
+ rexmpp_xml_add_attr(presence, "type", "unavailable");
rexmpp_send(s, presence);
free(full_jid);
}
@@ -654,25 +612,26 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
return;
}
if (! strcmp(word, "list")) {
- xmlNodePtr item;
+ rexmpp_xml_t *item;
for (item = s->roster_items;
item != NULL;
- item = xmlNextElementSibling(item)) {
- char *item_jid = xmlGetProp(item, "jid");
- char *item_ask = xmlGetProp(item, "ask");
- char *item_subscription = xmlGetProp(item, "subscription");
+ item = item->next) {
+ const char *item_jid = rexmpp_xml_find_attr_val(item, "jid");
+ const char *item_ask = rexmpp_xml_find_attr_val(item, "ask");
+ const char *item_subscription =
+ rexmpp_xml_find_attr_val(item, "subscription");
char *item_presence = "unavailable";
if (s->track_roster_presence) {
for (presence = s->roster_presence;
presence != NULL;
- presence = xmlNextElementSibling(presence)) {
- char *presence_from = xmlGetProp(presence, "from");
+ presence = presence->next) {
+ const char *presence_from =
+ rexmpp_xml_find_attr_val(presence, "from");
if (presence_from != NULL) {
rexmpp_jid_parse(presence_from, &jid);
if (! strcmp(jid.bare, item_jid)) {
item_presence = "available";
}
- free(presence_from);
}
}
}
@@ -681,28 +640,19 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
"presence = %s\n",
item_jid, item_subscription, item_ask,
item_presence);
- if (item_jid != NULL) {
- free(item_jid);
- }
- if (item_ask != NULL) {
- free(item_ask);
- }
- if (item_subscription != NULL) {
- free(item_subscription);
- }
}
} else if (! strcmp(word, "delete")) {
word = strtok_r(NULL, " ", &words_save_ptr);
if (word == NULL) {
return;
}
- xmlNodePtr delete_item = xmlNewNode(NULL, "item");
- delete_item->ns = xmlNewNs(delete_item, "jabber:iq:roster", NULL);
- xmlNewProp(delete_item, "jid", word);
- xmlNewProp(delete_item, "subscription", "remove");
- xmlNodePtr delete_query = xmlNewNode(NULL, "query");
- delete_query->ns = xmlNewNs(delete_query, "jabber:iq:roster", NULL);
- xmlAddChild(delete_query, delete_item);
+ rexmpp_xml_t *delete_item =
+ rexmpp_xml_new_elem("item", "jabber:iq:roster");
+ rexmpp_xml_add_attr(delete_item, "jid", word);
+ rexmpp_xml_add_attr(delete_item, "subscription", "remove");
+ rexmpp_xml_t *delete_query =
+ rexmpp_xml_new_elem("query", "jabber:iq:roster");
+ rexmpp_xml_add_child(delete_query, delete_item);
rexmpp_iq_new(s, "set", NULL, delete_query,
rexmpp_console_roster_deleted, NULL);
} else if (! strcmp(word, "add")) {
@@ -710,13 +660,13 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
if (word == NULL) {
return;
}
- xmlNodePtr delete_item = xmlNewNode(NULL, "item");
- delete_item->ns = xmlNewNs(delete_item, "jabber:iq:roster", NULL);
- xmlNewProp(delete_item, "jid", word);
- xmlNodePtr delete_query = xmlNewNode(NULL, "query");
- delete_query->ns = xmlNewNs(delete_query, "jabber:iq:roster", NULL);
- xmlAddChild(delete_query, delete_item);
- rexmpp_iq_new(s, "set", NULL, delete_query,
+ rexmpp_xml_t *add_item =
+ rexmpp_xml_new_elem("item", "jabber:iq:roster");
+ rexmpp_xml_add_attr(add_item, "jid", word);
+ rexmpp_xml_t *add_query =
+ rexmpp_xml_new_elem("query", "jabber:iq:roster");
+ rexmpp_xml_add_child(add_query, add_item);
+ rexmpp_iq_new(s, "set", NULL, add_query,
rexmpp_console_roster_added, NULL);
}
}
@@ -731,9 +681,10 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
if (word == NULL) {
return;
}
- presence = rexmpp_xml_add_id(s, xmlNewNode(NULL, "presence"));
- xmlNewProp(presence, "to", word);
- xmlNewProp(presence, "type", "subscribe");
+ presence = rexmpp_xml_new_elem("presence", "jabber:client");
+ rexmpp_xml_add_id(s, presence);
+ rexmpp_xml_add_attr(presence, "to", word);
+ rexmpp_xml_add_attr(presence, "type", "subscribe");
rexmpp_send(s, presence);
}
if (! strcmp(word, "approve")) {
@@ -741,9 +692,10 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
if (word == NULL) {
return;
}
- presence = rexmpp_xml_add_id(s, xmlNewNode(NULL, "presence"));
- xmlNewProp(presence, "to", word);
- xmlNewProp(presence, "type", "subscribed");
+ presence = rexmpp_xml_new_elem("presence", "jabber:client");
+ rexmpp_xml_add_id(s, presence);
+ rexmpp_xml_add_attr(presence, "to", word);
+ rexmpp_xml_add_attr(presence, "type", "subscribed");
rexmpp_send(s, presence);
}
if (! strcmp(word, "deny")) {
@@ -751,9 +703,10 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
if (word == NULL) {
return;
}
- presence = rexmpp_xml_add_id(s, xmlNewNode(NULL, "presence"));
- xmlNewProp(presence, "to", word);
- xmlNewProp(presence, "type", "unsubscribed");
+ presence = rexmpp_xml_new_elem("presence", "jabber:client");
+ rexmpp_xml_add_id(s, presence);
+ rexmpp_xml_add_attr(presence, "to", word);
+ rexmpp_xml_add_attr(presence, "type", "unsubscribed");
rexmpp_send(s, presence);
}
}
@@ -773,7 +726,7 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
char *sid = strtok_r(NULL, " ", &words_save_ptr);
if (sid != NULL) {
rexmpp_jingle_session_terminate(s, sid,
- rexmpp_xml_new_node("success",
+ rexmpp_xml_new_elem("success",
"urn:xmpp:jingle:1"),
NULL);
}
@@ -781,7 +734,7 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
char *sid = strtok_r(NULL, " ", &words_save_ptr);
if (sid != NULL) {
rexmpp_jingle_session_terminate(s, sid,
- rexmpp_xml_new_node("decline",
+ rexmpp_xml_new_elem("decline",
"urn:xmpp:jingle:1"),
NULL);
}
@@ -824,8 +777,8 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
if (jid == NULL) {
return;
}
- xmlNodePtr query =
- rexmpp_xml_new_node("query",
+ rexmpp_xml_t *query =
+ rexmpp_xml_new_elem("query",
"http://jabber.org/protocol/disco#info");
rexmpp_iq_new(s, "get", jid, query, rexmpp_console_disco_info, NULL);
}
@@ -834,8 +787,8 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
if (jid == NULL) {
return;
}
- xmlNodePtr query =
- rexmpp_xml_new_node("query",
+ rexmpp_xml_t *query =
+ rexmpp_xml_new_elem("query",
"http://jabber.org/protocol/disco#items");
rexmpp_iq_new(s, "get", jid, query, rexmpp_console_disco_items, NULL);
}
@@ -865,27 +818,32 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
if (! strcmp(word, "blocklist")) {
word = strtok_r(NULL, " ", &words_save_ptr);
if (word == NULL) {
- xmlNodePtr bl = rexmpp_xml_new_node("blocklist", "urn:xmpp:blocking");
+ rexmpp_xml_t *bl =
+ rexmpp_xml_new_elem("blocklist", "urn:xmpp:blocking");
rexmpp_iq_new(s, "get", NULL, bl, rexmpp_console_blocklist, NULL);
} else if (! strcmp(word, "block")) {
char *jid = strtok_r(NULL, " ", &words_save_ptr);
if (jid == NULL) {
return;
}
- xmlNodePtr bl = rexmpp_xml_new_node("block", "urn:xmpp:blocking");
- xmlNodePtr item = rexmpp_xml_new_node("item", "urn:xmpp:blocking");
- xmlNewProp(item, "jid", jid);
- xmlAddChild(bl, item);
+ rexmpp_xml_t *bl =
+ rexmpp_xml_new_elem("block", "urn:xmpp:blocking");
+ rexmpp_xml_t *item =
+ rexmpp_xml_new_elem("item", "urn:xmpp:blocking");
+ rexmpp_xml_add_attr(item, "jid", jid);
+ rexmpp_xml_add_child(bl, item);
rexmpp_iq_new(s, "set", NULL, bl, rexmpp_console_blocklist_blocked, NULL);
} else if (! strcmp(word, "unblock")) {
char *jid = strtok_r(NULL, " ", &words_save_ptr);
if (jid == NULL) {
return;
}
- xmlNodePtr bl = rexmpp_xml_new_node("unblock", "urn:xmpp:blocking");
- xmlNodePtr item = rexmpp_xml_new_node("item", "urn:xmpp:blocking");
- xmlNewProp(item, "jid", jid);
- xmlAddChild(bl, item);
+ rexmpp_xml_t *bl =
+ rexmpp_xml_new_elem("unblock", "urn:xmpp:blocking");
+ rexmpp_xml_t *item =
+ rexmpp_xml_new_elem("item", "urn:xmpp:blocking");
+ rexmpp_xml_add_attr(item, "jid", jid);
+ rexmpp_xml_add_child(bl, item);
rexmpp_iq_new(s, "set", NULL, bl, rexmpp_console_blocklist_unblocked, NULL);
}
}
diff --git a/src/rexmpp_console.h b/src/rexmpp_console.h
index 85e3d75..bb2aed7 100644
--- a/src/rexmpp_console.h
+++ b/src/rexmpp_console.h
@@ -11,8 +11,8 @@
#include "rexmpp.h"
-void rexmpp_console_on_send (rexmpp_t *s, xmlNodePtr node);
-void rexmpp_console_on_recv (rexmpp_t *s, xmlNodePtr node);
+void rexmpp_console_on_send (rexmpp_t *s, rexmpp_xml_t *node);
+void rexmpp_console_on_recv (rexmpp_t *s, rexmpp_xml_t *node);
void rexmpp_console_on_run (rexmpp_t *s, rexmpp_err_t result);
void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len);
diff --git a/src/rexmpp_http_upload.c b/src/rexmpp_http_upload.c
index 62d371b..2552771 100644
--- a/src/rexmpp_http_upload.c
+++ b/src/rexmpp_http_upload.c
@@ -18,6 +18,7 @@
#endif
#include "rexmpp.h"
+#include "rexmpp_xml.h"
#include "rexmpp_http_upload.h"
@@ -43,21 +44,21 @@ void rexmpp_upload_task_finish (struct rexmpp_http_upload_task *task) {
void rexmpp_http_upload_slot_cb (rexmpp_t *s,
void *ptr,
- xmlNodePtr request,
- xmlNodePtr response,
+ rexmpp_xml_t *request,
+ rexmpp_xml_t *response,
int success)
{
(void)request;
struct rexmpp_http_upload_task *task = ptr;
if (success) {
- xmlNodePtr slot = rexmpp_xml_find_child(response, "urn:xmpp:http:upload:0", "slot");
- xmlNodePtr put = rexmpp_xml_find_child(slot, "urn:xmpp:http:upload:0", "put");
- xmlNodePtr get = rexmpp_xml_find_child(slot, "urn:xmpp:http:upload:0", "get");
+ rexmpp_xml_t *slot = rexmpp_xml_find_child(response, "urn:xmpp:http:upload:0", "slot");
+ rexmpp_xml_t *put = rexmpp_xml_find_child(slot, "urn:xmpp:http:upload:0", "put");
+ rexmpp_xml_t *get = rexmpp_xml_find_child(slot, "urn:xmpp:http:upload:0", "get");
if (put != NULL && get != NULL) {
- char *put_url = xmlGetProp(put, "url");
- char *get_url = xmlGetProp(get, "url");
+ const char *put_url = rexmpp_xml_find_attr_val(put, "url");
+ const char *get_url = rexmpp_xml_find_attr_val(get, "url");
if (put_url != NULL && get_url != NULL) {
- task->get_url = get_url;
+ task->get_url = strdup(get_url);
CURL *ce = curl_easy_init();
curl_easy_setopt(ce, CURLOPT_PRIVATE, task);
@@ -65,11 +66,11 @@ void rexmpp_http_upload_slot_cb (rexmpp_t *s,
curl_easy_setopt(ce, CURLOPT_READDATA, task->fh);
curl_easy_setopt(ce, CURLOPT_URL, put_url);
- xmlNodePtr header = xmlFirstElementChild(put);
+ rexmpp_xml_t *header = rexmpp_xml_first_elem_child(put);
while (header) {
- char *header_name = xmlGetProp(header, "name");
+ const char *header_name = rexmpp_xml_find_attr_val(header, "name");
if (header_name != NULL) {
- char *header_str = xmlNodeGetContent(header);
+ const char *header_str = rexmpp_xml_text_child(header);
if (header_str != NULL) {
size_t full_header_str_len = strlen(header_name) + 3 + strlen(header_str);
char *full_header_str = malloc(full_header_str_len);
@@ -78,11 +79,9 @@ void rexmpp_http_upload_slot_cb (rexmpp_t *s,
task->http_headers =
curl_slist_append(task->http_headers, full_header_str);
free(full_header_str);
- free(header_str);
}
- free(header_name);
}
- header = header->next;
+ header = rexmpp_xml_next_elem_sibling(header);
}
curl_easy_setopt(ce, CURLOPT_HTTPHEADER, task->http_headers);
@@ -91,12 +90,6 @@ void rexmpp_http_upload_slot_cb (rexmpp_t *s,
return;
} else {
rexmpp_log(s, LOG_ERR, "Unexpected structure for a HTTP file upload slot.");
- if (get_url != NULL) {
- free(get_url);
- }
- }
- if (put_url != NULL) {
- free(put_url);
}
} else {
rexmpp_log(s, LOG_ERR, "Unexpected structure for a HTTP file upload slot.");
@@ -109,8 +102,8 @@ void rexmpp_http_upload_slot_cb (rexmpp_t *s,
void rexmpp_http_upload_feature_cb (rexmpp_t *s,
void *ptr,
- xmlNodePtr request,
- xmlNodePtr response,
+ rexmpp_xml_t *request,
+ rexmpp_xml_t *response,
int success)
{
(void)response;
@@ -120,17 +113,17 @@ void rexmpp_http_upload_feature_cb (rexmpp_t *s,
rexmpp_upload_task_finish(task);
return;
}
- xmlNodePtr req = rexmpp_xml_new_node("request", "urn:xmpp:http:upload:0");
- xmlNewProp(req, "filename", task->fname);
+ rexmpp_xml_t *req =
+ rexmpp_xml_new_elem("request", "urn:xmpp:http:upload:0");
+ rexmpp_xml_add_attr(req, "filename", task->fname);
char buf[11];
snprintf(buf, 11, "%u", task->fsize);
- xmlNewProp(req, "size", buf);
+ rexmpp_xml_add_attr(req, "size", buf);
if (task->content_type) {
- xmlNewProp(req, "content-type", task->content_type);
+ rexmpp_xml_add_attr(req, "content-type", task->content_type);
}
- char *to = xmlGetProp(request, "to");
+ const char *to = rexmpp_xml_find_attr_val(request, "to");
rexmpp_iq_new(s, "get", to, req, rexmpp_http_upload_slot_cb, task);
- free(to);
}
rexmpp_err_t
diff --git a/src/rexmpp_jingle.c b/src/rexmpp_jingle.c
index 8499dc8..573c193 100644
--- a/src/rexmpp_jingle.c
+++ b/src/rexmpp_jingle.c
@@ -43,6 +43,7 @@ A/V calls over ICE-UDP + DTLS-SRTP:
#endif
#include "rexmpp.h"
+#include "rexmpp_xml.h"
#include "rexmpp_jingle.h"
#include "rexmpp_base64.h"
@@ -71,15 +72,15 @@ void rexmpp_jingle_session_destroy (rexmpp_jingle_session_t *session) {
free(session->sid);
}
if (session->initiate != NULL) {
- xmlFreeNodeList(session->initiate);
+ rexmpp_xml_free_list(session->initiate);
}
if (session->accept != NULL) {
- xmlFreeNodeList(session->accept);
+ rexmpp_xml_free_list(session->accept);
}
if (session->ibb_fh != NULL) {
fclose(session->ibb_fh);
}
- #ifdef ENABLE_CALLS
+#ifdef ENABLE_CALLS
if (session->type == REXMPP_JINGLE_SESSION_MEDIA) {
int i;
for (i = 0; i < 2; i++) {
@@ -126,7 +127,7 @@ void rexmpp_jingle_session_destroy (rexmpp_jingle_session_t *session) {
session->turn_password = NULL;
}
}
- #endif
+#endif
free(session);
}
@@ -267,8 +268,8 @@ void rexmpp_jingle_stop (rexmpp_t *s) {
void rexmpp_jingle_accept_file_cb (rexmpp_t *s,
void *ptr,
- xmlNodePtr request,
- xmlNodePtr response,
+ rexmpp_xml_t *request,
+ rexmpp_xml_t *response,
int success)
{
(void)request;
@@ -292,15 +293,16 @@ rexmpp_jingle_accept_file (rexmpp_t *s,
path, strerror(errno));
return REXMPP_E_OTHER;
}
- xmlNodePtr jingle = session->initiate;
- xmlNodePtr content = rexmpp_xml_find_child(jingle, "urn:xmpp:jingle:1", "content");
+ rexmpp_xml_t *jingle = session->initiate;
+ rexmpp_xml_t *content = rexmpp_xml_find_child(jingle, "urn:xmpp:jingle:1", "content");
- xmlNodePtr new_jingle = rexmpp_xml_new_node("jingle", "urn:xmpp:jingle:1");
- xmlNewProp(new_jingle, "action", "session-accept");
- xmlNewProp(new_jingle, "responder", s->assigned_jid.full);
- xmlNewProp(new_jingle, "sid", session->sid);
- xmlAddChild(new_jingle, xmlCopyNode(content, 1));
- session->accept = xmlCopyNode(new_jingle, 1);
+ rexmpp_xml_t *new_jingle =
+ rexmpp_xml_new_elem("jingle", "urn:xmpp:jingle:1");
+ rexmpp_xml_add_attr(new_jingle, "action", "session-accept");
+ rexmpp_xml_add_attr(new_jingle, "responder", s->assigned_jid.full);
+ rexmpp_xml_add_attr(new_jingle, "sid", session->sid);
+ rexmpp_xml_add_child(new_jingle, rexmpp_xml_clone(content));
+ session->accept = rexmpp_xml_clone(new_jingle);
return rexmpp_iq_new(s, "set", session->jid, new_jingle,
rexmpp_jingle_accept_file_cb, strdup(session->sid));
}
@@ -319,8 +321,8 @@ rexmpp_jingle_accept_file_by_id (rexmpp_t *s,
void rexmpp_jingle_session_terminate_cb (rexmpp_t *s,
void *ptr,
- xmlNodePtr request,
- xmlNodePtr response,
+ rexmpp_xml_t *request,
+ rexmpp_xml_t *response,
int success)
{
(void)request;
@@ -336,24 +338,27 @@ void rexmpp_jingle_session_terminate_cb (rexmpp_t *s,
rexmpp_err_t
rexmpp_jingle_session_terminate (rexmpp_t *s,
const char *sid,
- xmlNodePtr reason_node,
+ rexmpp_xml_t *reason_node,
const char *reason_text)
{
rexmpp_jingle_session_t *session = rexmpp_jingle_session_by_id(s, sid);
if (session == NULL) {
return REXMPP_E_OTHER;
}
- xmlNodePtr jingle = rexmpp_xml_new_node("jingle", "urn:xmpp:jingle:1");
- xmlNewProp(jingle, "action", "session-terminate");
- xmlNewProp(jingle, "sid", sid);
- xmlNodePtr reason = rexmpp_xml_new_node("reason", "urn:xmpp:jingle:1");
+ rexmpp_xml_t *jingle =
+ rexmpp_xml_new_elem("jingle", "urn:xmpp:jingle:1");
+ rexmpp_xml_add_attr(jingle, "action", "session-terminate");
+ rexmpp_xml_add_attr(jingle, "sid", sid);
+ rexmpp_xml_t *reason =
+ rexmpp_xml_new_elem("reason", "urn:xmpp:jingle:1");
if (reason_text != NULL) {
- xmlNodePtr text = rexmpp_xml_new_node("text", "urn:xmpp:jingle:1");
- xmlNodeAddContent(text, reason_text);
- xmlAddChild(reason, text);
+ rexmpp_xml_t *text =
+ rexmpp_xml_new_elem("text", "urn:xmpp:jingle:1");
+ rexmpp_xml_add_text(text, reason_text);
+ rexmpp_xml_add_child(reason, text);
}
- xmlAddChild(reason, reason_node);
- xmlAddChild(jingle, reason);
+ rexmpp_xml_add_child(reason, reason_node);
+ rexmpp_xml_add_child(jingle, reason);
rexmpp_err_t ret = rexmpp_iq_new(s, "set", session->jid, jingle,
rexmpp_jingle_session_terminate_cb,
strdup(sid));
@@ -363,8 +368,8 @@ rexmpp_jingle_session_terminate (rexmpp_t *s,
void rexmpp_jingle_send_file_cb (rexmpp_t *s,
void *ptr,
- xmlNodePtr request,
- xmlNodePtr response,
+ rexmpp_xml_t *request,
+ rexmpp_xml_t *response,
int success)
{
(void)request;
@@ -416,31 +421,33 @@ rexmpp_jingle_send_file (rexmpp_t *s,
char *sid = rexmpp_gen_id(s);
char *ibb_sid = rexmpp_gen_id(s);
- xmlNodePtr jingle = rexmpp_xml_new_node("jingle", "urn:xmpp:jingle:1");
- xmlNewProp(jingle, "action", "session-initiate");
- xmlNewProp(jingle, "sid", sid);
- xmlNewProp(jingle, "initiator", s->assigned_jid.full);
-
- xmlNodePtr content = rexmpp_xml_new_node("content", "urn:xmpp:jingle:1");
- xmlNewProp(content, "creator", "initiator");
- xmlNewProp(content, "name", "IBB file");
- xmlAddChild(jingle, content);
-
- xmlNodePtr transport =
- rexmpp_xml_new_node("transport", "urn:xmpp:jingle:transports:ibb:1");
- xmlNewProp(transport, "block-size", "4096");
- xmlNewProp(transport, "sid", ibb_sid);
- xmlAddChild(content, transport);
- xmlNodePtr description =
- rexmpp_xml_new_node("description", "urn:xmpp:jingle:apps:file-transfer:5");
- xmlAddChild(content, description);
- xmlNodePtr file =
- rexmpp_xml_new_node("file", "urn:xmpp:jingle:apps:file-transfer:5");
- xmlAddChild(description, file);
- xmlNodePtr file_name =
- rexmpp_xml_new_node("name", "urn:xmpp:jingle:apps:file-transfer:5");
- xmlNodeAddContent(file_name, basename(path));
- xmlAddChild(file, file_name);
+ rexmpp_xml_t *jingle =
+ rexmpp_xml_new_elem("jingle", "urn:xmpp:jingle:1");
+ rexmpp_xml_add_attr(jingle, "action", "session-initiate");
+ rexmpp_xml_add_attr(jingle, "sid", sid);
+ rexmpp_xml_add_attr(jingle, "initiator", s->assigned_jid.full);
+
+ rexmpp_xml_t *content =
+ rexmpp_xml_new_elem("content", "urn:xmpp:jingle:1");
+ rexmpp_xml_add_attr(content, "creator", "initiator");
+ rexmpp_xml_add_attr(content, "name", "IBB file");
+ rexmpp_xml_add_child(jingle, content);
+
+ rexmpp_xml_t *transport =
+ rexmpp_xml_new_elem("transport", "urn:xmpp:jingle:transports:ibb:1");
+ rexmpp_xml_add_attr(transport, "block-size", "4096");
+ rexmpp_xml_add_attr(transport, "sid", ibb_sid);
+ rexmpp_xml_add_child(content, transport);
+ rexmpp_xml_t *description =
+ rexmpp_xml_new_elem("description", "urn:xmpp:jingle:apps:file-transfer:5");
+ rexmpp_xml_add_child(content, description);
+ rexmpp_xml_t *file =
+ rexmpp_xml_new_elem("file", "urn:xmpp:jingle:apps:file-transfer:5");
+ rexmpp_xml_add_child(description, file);
+ rexmpp_xml_t *file_name =
+ rexmpp_xml_new_elem("name", "urn:xmpp:jingle:apps:file-transfer:5");
+ rexmpp_xml_add_text(file_name, basename(path));
+ rexmpp_xml_add_child(file, file_name);
char *hash_base64 = NULL;
size_t hash_base64_len = 0;
@@ -448,11 +455,12 @@ rexmpp_jingle_send_file (rexmpp_t *s,
gcry_md_get_algo_dlen(GCRY_MD_SHA256),
&hash_base64,
&hash_base64_len);
- xmlNodePtr file_hash = rexmpp_xml_new_node("hash", "urn:xmpp:hashes:2");
- xmlNewProp(file_hash, "algo", "sha-256");
- xmlNodeAddContent(file_hash, hash_base64);
+ rexmpp_xml_t *file_hash =
+ rexmpp_xml_new_elem("hash", "urn:xmpp:hashes:2");
+ rexmpp_xml_add_attr(file_hash, "algo", "sha-256");
+ rexmpp_xml_add_text(file_hash, hash_base64);
free(hash_base64);
- xmlAddChild(file, file_hash);
+ rexmpp_xml_add_child(file, file_hash);
hash_base64 = NULL;
hash_base64_len = 0;
@@ -460,26 +468,26 @@ rexmpp_jingle_send_file (rexmpp_t *s,
gcry_md_get_algo_dlen(GCRY_MD_SHA3_256),
&hash_base64,
&hash_base64_len);
- file_hash = rexmpp_xml_new_node("hash", "urn:xmpp:hashes:2");
- xmlNewProp(file_hash, "algo", "sha3-256");
- xmlNodeAddContent(file_hash, hash_base64);
+ file_hash = rexmpp_xml_new_elem("hash", "urn:xmpp:hashes:2");
+ rexmpp_xml_add_attr(file_hash, "algo", "sha3-256");
+ rexmpp_xml_add_text(file_hash, hash_base64);
free(hash_base64);
- xmlAddChild(file, file_hash);
+ rexmpp_xml_add_child(file, file_hash);
gcry_md_close(hd);
long fsize = ftell(fh);
fseek(fh, 0, SEEK_SET);
snprintf(buf, 11, "%ld", fsize);
- xmlNodePtr file_size =
- rexmpp_xml_new_node("size", "urn:xmpp:jingle:apps:file-transfer:5");
- xmlNodeAddContent(file_size, buf);
- xmlAddChild(file, file_size);
+ rexmpp_xml_t *file_size =
+ rexmpp_xml_new_elem("size", "urn:xmpp:jingle:apps:file-transfer:5");
+ rexmpp_xml_add_text(file_size, buf);
+ rexmpp_xml_add_child(file, file_size);
rexmpp_jingle_session_t *sess =
rexmpp_jingle_session_create(s, strdup(jid), sid, REXMPP_JINGLE_SESSION_FILE, 1);
if (sess != NULL) {
- sess->initiate = xmlCopyNode(jingle, 1);
+ sess->initiate = rexmpp_xml_clone(jingle);
sess->ibb_sid = ibb_sid;
sess->ibb_fh = fh;
return rexmpp_iq_new(s, "set", sess->jid, jingle,
@@ -492,8 +500,8 @@ rexmpp_jingle_send_file (rexmpp_t *s,
void rexmpp_jingle_ibb_close_cb (rexmpp_t *s,
void *ptr,
- xmlNodePtr request,
- xmlNodePtr response,
+ rexmpp_xml_t *request,
+ rexmpp_xml_t *response,
int success)
{
(void)request;
@@ -509,8 +517,8 @@ void rexmpp_jingle_ibb_close_cb (rexmpp_t *s,
void rexmpp_jingle_ibb_send_cb (rexmpp_t *s,
void *ptr,
- xmlNodePtr request,
- xmlNodePtr response,
+ rexmpp_xml_t *request,
+ rexmpp_xml_t *response,
int success)
{
(void)request;
@@ -529,8 +537,9 @@ void rexmpp_jingle_ibb_send_cb (rexmpp_t *s,
return;
}
if (feof(session->ibb_fh)) {
- xmlNodePtr close = rexmpp_xml_new_node("close", "http://jabber.org/protocol/ibb");
- xmlNewProp(close, "sid", session->ibb_sid);
+ rexmpp_xml_t *close =
+ rexmpp_xml_new_elem("close", "http://jabber.org/protocol/ibb");
+ rexmpp_xml_add_attr(close, "sid", session->ibb_sid);
rexmpp_iq_new(s, "set", session->jid, close,
rexmpp_jingle_ibb_close_cb, sid);
return;
@@ -538,15 +547,16 @@ void rexmpp_jingle_ibb_send_cb (rexmpp_t *s,
char buf[4096];
size_t len = fread(buf, 1, 4096, session->ibb_fh);
if (len > 0) {
- xmlNodePtr data = rexmpp_xml_new_node("data", "http://jabber.org/protocol/ibb");
- xmlNewProp(data, "sid", session->ibb_sid);
+ rexmpp_xml_t *data =
+ rexmpp_xml_new_elem("data", "http://jabber.org/protocol/ibb");
+ rexmpp_xml_add_attr(data, "sid", session->ibb_sid);
char *out = NULL;
size_t out_len = 0;
rexmpp_base64_to(buf, len, &out, &out_len);
- xmlNodeAddContent(data, out);
+ rexmpp_xml_add_text(data, out);
free(out);
snprintf(buf, 11, "%u", session->ibb_seq);
- xmlNewProp(data, "seq", buf);
+ rexmpp_xml_add_attr(data, "seq", buf);
session->ibb_seq++;
rexmpp_iq_new(s, "set", session->jid, data,
rexmpp_jingle_ibb_send_cb, sid);
@@ -554,7 +564,7 @@ void rexmpp_jingle_ibb_send_cb (rexmpp_t *s,
} else {
rexmpp_log(s, LOG_ERR, "Failed to read from a file: %s ", strerror(errno));
rexmpp_jingle_session_terminate(s, sid,
- rexmpp_xml_new_node("media-error",
+ rexmpp_xml_new_elem("media-error",
"urn:xmpp:jingle:1"),
"File reading error");
}
@@ -565,8 +575,8 @@ void rexmpp_jingle_ibb_send_cb (rexmpp_t *s,
#ifdef ENABLE_CALLS
void rexmpp_jingle_call_cb (rexmpp_t *s,
void *ptr,
- xmlNodePtr request,
- xmlNodePtr response,
+ rexmpp_xml_t *request,
+ rexmpp_xml_t *response,
int success)
{
(void)request;
@@ -581,31 +591,29 @@ void rexmpp_jingle_call_cb (rexmpp_t *s,
void
rexmpp_jingle_ice_udp_add_remote (rexmpp_jingle_session_t *sess,
- xmlNodePtr transport)
+ rexmpp_xml_t *transport)
{
if (sess->ice_agent == NULL) {
/* Must be an incoming call; just add candidates to
session-initiate's transport. */
- xmlNodePtr old_transport =
+ rexmpp_xml_t *old_transport =
rexmpp_xml_find_child(rexmpp_xml_find_child(sess->initiate,
"urn:xmpp:jingle:1",
"content"),
"urn:xmpp:jingle:transports:ice-udp:1",
"transport");
- xmlNodePtr candidate = xmlFirstElementChild(transport);
+ rexmpp_xml_t *candidate = rexmpp_xml_first_elem_child(transport);
while (rexmpp_xml_match(candidate, "urn:xmpp:jingle:transports:ice-udp:1",
"candidate")) {
- xmlAddChild(old_transport, xmlCopyNode(candidate, 1));
- candidate = candidate->next;
+ rexmpp_xml_add_child(old_transport, rexmpp_xml_clone(candidate));
+ candidate = rexmpp_xml_next_elem_sibling(candidate);
}
return;
}
- char *ufrag = xmlGetProp(transport, "ufrag");
- char *password = xmlGetProp(transport, "pwd");
+ const char *ufrag = rexmpp_xml_find_attr_val(transport, "ufrag");
+ const char *password = rexmpp_xml_find_attr_val(transport, "pwd");
nice_agent_set_remote_credentials(sess->ice_agent, sess->ice_stream_id,
ufrag, password);
- free(ufrag);
- free(password);
int component_id;
@@ -614,12 +622,12 @@ rexmpp_jingle_ice_udp_add_remote (rexmpp_jingle_session_t *sess,
nice_agent_get_remote_candidates(sess->ice_agent,
sess->ice_stream_id,
component_id);
- xmlNodePtr candidate = xmlFirstElementChild(transport);
+ rexmpp_xml_t *candidate = rexmpp_xml_first_elem_child(transport);
while (rexmpp_xml_match(candidate, "urn:xmpp:jingle:transports:ice-udp:1",
"candidate")) {
- char *component = xmlGetProp(candidate, "component");
+ const char *component = rexmpp_xml_find_attr_val(candidate, "component");
if (component[0] == component_id + '0') {
- char *type_str = xmlGetProp(candidate, "type");
+ const char *type_str = rexmpp_xml_find_attr_val(candidate, "type");
int type_n = NICE_CANDIDATE_TYPE_HOST;
if (strcmp(type_str, "host") == 0) {
type_n = NICE_CANDIDATE_TYPE_HOST;
@@ -630,38 +638,32 @@ rexmpp_jingle_ice_udp_add_remote (rexmpp_jingle_session_t *sess,
} else if (strcmp(type_str, "relay") == 0) {
type_n = NICE_CANDIDATE_TYPE_RELAYED;
}
- free(type_str);
NiceCandidate *c = nice_candidate_new(type_n);
c->component_id = component_id;
c->stream_id = sess->ice_stream_id;
- char *foundation = xmlGetProp(candidate, "foundation");
+ const char *foundation = rexmpp_xml_find_attr_val(candidate, "foundation");
strncpy(c->foundation, foundation, NICE_CANDIDATE_MAX_FOUNDATION - 1);
c->foundation[NICE_CANDIDATE_MAX_FOUNDATION - 1] = 0;
- free(foundation);
c->transport = NICE_CANDIDATE_TRANSPORT_UDP;
- char *priority = xmlGetProp(candidate, "priority");
+ const char *priority = rexmpp_xml_find_attr_val(candidate, "priority");
c->priority = atoi(priority);
- free(priority);
- char *ip = xmlGetProp(candidate, "ip");
+ const char *ip = rexmpp_xml_find_attr_val(candidate, "ip");
if (! nice_address_set_from_string(&c->addr, ip)) {
rexmpp_log(sess->s, LOG_ERR,
"Failed to parse an ICE-UDP candidate's address: %s",
ip);
}
- free(ip);
- char *port = xmlGetProp(candidate, "port");
+ const char *port = rexmpp_xml_find_attr_val(candidate, "port");
nice_address_set_port(&c->addr, atoi(port));
- free(port);
remote_candidates = g_slist_prepend(remote_candidates, c);
}
- free(component);
- candidate = candidate->next;
+ candidate = rexmpp_xml_next_elem_sibling(candidate);
}
if (remote_candidates != NULL) {
nice_agent_set_remote_candidates(sess->ice_agent, sess->ice_stream_id,
@@ -674,7 +676,7 @@ rexmpp_jingle_ice_udp_add_remote (rexmpp_jingle_session_t *sess,
/* Checks whether we are in the active (client) role for DTLS, based
on either "session-initiate" or "session-accept" message. */
int rexmpp_jingle_dtls_is_active (rexmpp_jingle_session_t *sess, int in_initiate) {
- xmlNodePtr fingerprint =
+ rexmpp_xml_t *fingerprint =
rexmpp_xml_find_child
(rexmpp_xml_find_child
(rexmpp_xml_find_child
@@ -687,7 +689,7 @@ int rexmpp_jingle_dtls_is_active (rexmpp_jingle_session_t *sess, int in_initiate
in_initiate ? "initiate" : "accept");
return 0;
}
- char *fingerprint_setup = xmlGetProp(fingerprint, "setup");
+ const char *fingerprint_setup = rexmpp_xml_find_attr_val(fingerprint, "setup");
if (fingerprint_setup == NULL) {
rexmpp_log(sess->s, LOG_ERR, "No 'setup' attribute for a fingerprint element");
return 0;
@@ -706,15 +708,14 @@ int rexmpp_jingle_dtls_is_active (rexmpp_jingle_session_t *sess, int in_initiate
active = (strcmp(fingerprint_setup, "active") == 0);
}
}
- free(fingerprint_setup);
return active;
}
void rexmpp_transport_info_call_cb (rexmpp_t *s,
void *ptr,
- xmlNodePtr request,
- xmlNodePtr response,
+ rexmpp_xml_t *request,
+ rexmpp_xml_t *response,
int success)
{
(void)request;
@@ -762,90 +763,87 @@ rexmpp_jingle_candidate_gathering_done_cb (NiceAgent *agent,
}
gnutls_free(cert_list);
- xmlNodePtr jingle = rexmpp_xml_new_node("jingle", "urn:xmpp:jingle:1");
- xmlNewProp(jingle, "sid", sess->sid);
+ rexmpp_xml_t *jingle = rexmpp_xml_new_elem("jingle", "urn:xmpp:jingle:1");
+ rexmpp_xml_add_attr(jingle, "sid", sess->sid);
- xmlNodePtr content = rexmpp_xml_new_node("content", "urn:xmpp:jingle:1");
- xmlNewProp(content, "creator", "initiator");
- xmlNewProp(content, "senders", "both");
- xmlNodePtr description;
+ rexmpp_xml_t *content = rexmpp_xml_new_elem("content", "urn:xmpp:jingle:1");
+ rexmpp_xml_add_attr(content, "creator", "initiator");
+ rexmpp_xml_add_attr(content, "senders", "both");
+ rexmpp_xml_t *description;
if (sess->initiator) {
- xmlNewProp(jingle, "action", "session-initiate");
- xmlNewProp(jingle, "initiator", sess->s->assigned_jid.full);
- xmlNewProp(content, "name", "call");
+ rexmpp_xml_add_attr(jingle, "action", "session-initiate");
+ rexmpp_xml_add_attr(jingle, "initiator", sess->s->assigned_jid.full);
+ rexmpp_xml_add_attr(content, "name", "call");
/* https://datatracker.ietf.org/doc/html/rfc4568 */
- xmlNodePtr encryption =
- rexmpp_xml_new_node("encryption", "urn:xmpp:jingle:apps:rtp:1");
- xmlNewProp(encryption, "required", "true");
- xmlAddChild(content, encryption);
- xmlNodePtr crypto = rexmpp_xml_new_node("crypto", "urn:xmpp:jingle:apps:rtp:1");
- xmlNewProp(crypto, "crypto-suite", "AES_CM_128_HMAC_SHA1_80");
- xmlNewProp(crypto, "tag", "1");
- xmlAddChild(encryption, crypto);
-
- description = xmlCopyNode(sess->s->jingle_rtp_description, 1);
+ rexmpp_xml_t *encryption =
+ rexmpp_xml_new_elem("encryption", "urn:xmpp:jingle:apps:rtp:1");
+ rexmpp_xml_add_attr(encryption, "required", "true");
+ rexmpp_xml_add_child(content, encryption);
+ rexmpp_xml_t *crypto =
+ rexmpp_xml_new_elem("crypto", "urn:xmpp:jingle:apps:rtp:1");
+ rexmpp_xml_add_attr(crypto, "crypto-suite", "AES_CM_128_HMAC_SHA1_80");
+ rexmpp_xml_add_attr(crypto, "tag", "1");
+ rexmpp_xml_add_child(encryption, crypto);
+
+ description = rexmpp_xml_clone(sess->s->jingle_rtp_description);
} else {
- xmlNodePtr init_jingle = sess->initiate;
- xmlNodePtr init_content =
+ rexmpp_xml_t *init_jingle = sess->initiate;
+ rexmpp_xml_t *init_content =
rexmpp_xml_find_child(init_jingle, "urn:xmpp:jingle:1", "content");
- char *init_content_name = xmlGetProp(init_content, "name");
+ const char *init_content_name = rexmpp_xml_find_attr_val(init_content, "name");
if (init_content_name != NULL) {
- xmlNewProp(content, "name", init_content_name);
- free(init_content_name);
+ rexmpp_xml_add_attr(content, "name", init_content_name);
} else {
rexmpp_log(sess->s, LOG_ERR,
"Empty content name for Jingle session %s with %s",
sess->sid, sess->jid);
}
- xmlNewProp(jingle, "action", "session-accept");
- xmlNewProp(jingle, "initiator", sess->jid);
- xmlNewProp(jingle, "responder", sess->s->assigned_jid.full);
+ rexmpp_xml_add_attr(jingle, "action", "session-accept");
+ rexmpp_xml_add_attr(jingle, "initiator", sess->jid);
+ rexmpp_xml_add_attr(jingle, "responder", sess->s->assigned_jid.full);
- description = xmlCopyNode(sess->s->jingle_rtp_description, 2);
+ description = rexmpp_xml_clone(sess->s->jingle_rtp_description);
/* Find the first matching payload-type and add that */
- xmlNodePtr pl_type =
- xmlFirstElementChild(sess->s->jingle_rtp_description);
- xmlNodePtr selected_pl = NULL;
+ rexmpp_xml_t *pl_type =
+ rexmpp_xml_first_elem_child(sess->s->jingle_rtp_description);
+ rexmpp_xml_t *selected_pl = NULL;
while (pl_type != NULL && selected_pl == NULL) {
if (rexmpp_xml_match(pl_type, "urn:xmpp:jingle:apps:rtp:1", "payload-type")) {
- char *pl_id = xmlGetProp(pl_type, "id");
+ const char *pl_id = rexmpp_xml_find_attr_val(pl_type, "id");
if (pl_id != NULL) {
int pl_id_num = atoi(pl_id);
- xmlNodePtr proposed_pl_type =
- xmlFirstElementChild
+ rexmpp_xml_t *proposed_pl_type =
+ rexmpp_xml_first_elem_child
(rexmpp_xml_find_child
(rexmpp_xml_find_child(sess->initiate,
"urn:xmpp:jingle:1", "content"),
"urn:xmpp:jingle:apps:rtp:1", "description"));
while (proposed_pl_type != NULL && selected_pl == NULL) {
if (rexmpp_xml_match(proposed_pl_type, "urn:xmpp:jingle:apps:rtp:1", "payload-type")) {
- char *proposed_pl_id = xmlGetProp(proposed_pl_type, "id");
+ const char *proposed_pl_id = rexmpp_xml_find_attr_val(proposed_pl_type, "id");
if (proposed_pl_id != NULL) {
int proposed_pl_id_num = atoi(proposed_pl_id);
if (pl_id_num < 96 && pl_id_num == proposed_pl_id_num) {
selected_pl = pl_type;
} else {
- char *pl_name = xmlGetProp(pl_type, "name");
+ const char *pl_name = rexmpp_xml_find_attr_val(pl_type, "name");
if (pl_name != NULL) {
- char *proposed_pl_name = xmlGetProp(proposed_pl_type, "name");
+ const char *proposed_pl_name =
+ rexmpp_xml_find_attr_val(proposed_pl_type, "name");
if (proposed_pl_name != NULL) {
if (strcmp(pl_name, proposed_pl_name) == 0) {
/* todo: compare clock rates, numbers of
channels, parameters */
selected_pl = pl_type;
}
- free(proposed_pl_name);
}
- free(pl_name);
}
}
- free(proposed_pl_id);
}
}
- proposed_pl_type = proposed_pl_type->next;
+ proposed_pl_type = rexmpp_xml_next_elem_sibling(proposed_pl_type);
}
- free(pl_id);
} else {
rexmpp_log(sess->s, LOG_ERR,
"No 'id' specified for a pyaload-type element.");
@@ -854,7 +852,7 @@ rexmpp_jingle_candidate_gathering_done_cb (NiceAgent *agent,
pl_type = pl_type->next;
}
if (selected_pl != NULL) {
- xmlAddChild(description, xmlCopyNode(selected_pl, 1));
+ rexmpp_xml_add_child(description, rexmpp_xml_clone(selected_pl));
} else {
rexmpp_log(sess->s, LOG_ERR, "No suitable payload type found");
/* todo: fail if it's NULL, though it shouldn't happen, since
@@ -862,69 +860,70 @@ rexmpp_jingle_candidate_gathering_done_cb (NiceAgent *agent,
}
}
- xmlAddChild(jingle, content);
- xmlAddChild(content, description);
+ rexmpp_xml_add_child(jingle, content);
+ rexmpp_xml_add_child(content, description);
if (sess->rtcp_mux) {
- xmlNodePtr rtcp_mux =
- rexmpp_xml_new_node("rtcp-mux", "urn:xmpp:jingle:apps:rtp:1");
- xmlAddChild(description, rtcp_mux);
+ rexmpp_xml_t *rtcp_mux =
+ rexmpp_xml_new_elem("rtcp-mux", "urn:xmpp:jingle:apps:rtp:1");
+ rexmpp_xml_add_child(description, rtcp_mux);
}
- xmlNodePtr transport =
- rexmpp_xml_new_node("transport", "urn:xmpp:jingle:transports:ice-udp:1");
+ rexmpp_xml_t *transport =
+ rexmpp_xml_new_elem("transport", "urn:xmpp:jingle:transports:ice-udp:1");
gchar *ufrag = NULL;
gchar *password = NULL;
nice_agent_get_local_credentials(agent, stream_id, &ufrag, &password);
- xmlNewProp(transport, "ufrag", ufrag);
- xmlNewProp(transport, "pwd", password);
+ rexmpp_xml_add_attr(transport, "ufrag", ufrag);
+ rexmpp_xml_add_attr(transport, "pwd", password);
g_free(ufrag);
g_free(password);
- xmlAddChild(content, transport);
+ rexmpp_xml_add_child(content, transport);
int component_id;
- xmlNodePtr postponed_candidates = NULL;
+ rexmpp_xml_t *postponed_candidates = NULL;
for (component_id = 1; component_id <= (sess->rtcp_mux ? 1 : 2); component_id++) {
GSList *candidates = nice_agent_get_local_candidates(agent, stream_id, component_id);
GSList *cand_cur = candidates;
int cand_num = 0;
while (cand_cur != NULL) {
- xmlNodePtr candidate =
- rexmpp_xml_new_node("candidate", "urn:xmpp:jingle:transports:ice-udp:1");
+ rexmpp_xml_t *candidate =
+ rexmpp_xml_new_elem("candidate", "urn:xmpp:jingle:transports:ice-udp:1");
char buf[INET6_ADDRSTRLEN];
NiceCandidate *c = (NiceCandidate *)cand_cur->data;
snprintf(buf, 11, "%u", component_id);
- xmlNewProp(candidate, "component", buf);
- xmlNewProp(candidate, "foundation", c->foundation);
- xmlNewProp(candidate, "generation", "0");
+ rexmpp_xml_add_attr(candidate, "component", buf);
+ rexmpp_xml_add_attr(candidate, "foundation", c->foundation);
+ rexmpp_xml_add_attr(candidate, "generation", "0");
char *cid = rexmpp_gen_id(sess->s);
- xmlNewProp(candidate, "id", cid);
+ rexmpp_xml_add_attr(candidate, "id", cid);
free(cid);
nice_address_to_string(&c->addr, buf);
- xmlNewProp(candidate, "ip", buf);
+ rexmpp_xml_add_attr(candidate, "ip", buf);
snprintf(buf, 11, "%u", nice_address_get_port(&c->addr));
- xmlNewProp(candidate, "port", buf);
- xmlNewProp(candidate, "network", "0");
- xmlNewProp(candidate, "protocol", "udp");
+ rexmpp_xml_add_attr(candidate, "port", buf);
+ rexmpp_xml_add_attr(candidate, "network", "0");
+ rexmpp_xml_add_attr(candidate, "protocol", "udp");
snprintf(buf, 11, "%u", c->priority);
- xmlNewProp(candidate, "priority", buf);
+ rexmpp_xml_add_attr(candidate, "priority", buf);
char *nice_type[] = {"host", "srflx", "prflx", "relay"};
if (c->type < 4) {
- xmlNewProp(candidate, "type", nice_type[c->type]);
+ rexmpp_xml_add_attr(candidate, "type", nice_type[c->type]);
}
/* Can't send too many candidates, since stanza sizes are usually
- limited, and then it breaks the stream. Limiting to 10 per
- component, sending the rest later, via transport-info. */
+ limited, and then it breaks the stream. Limiting to 10 per
+ component, sending the rest later, via transport-info. */
if (cand_num < 10) {
- xmlAddChild(transport, candidate);
+ rexmpp_xml_add_child(transport, candidate);
} else {
- xmlNodePtr jingle_ti = rexmpp_xml_new_node("jingle", "urn:xmpp:jingle:1");
- xmlNewProp(jingle_ti, "sid", sess->sid);
- xmlNewProp(jingle_ti, "action", "transport-info");
- xmlNodePtr content_copy = xmlCopyNode(content, 2);
- xmlNodePtr transport_copy = xmlCopyNode(transport, 2);
- xmlAddChild(jingle_ti, content_copy);
- xmlAddChild(content_copy, transport_copy);
- xmlAddChild(transport_copy, candidate);
+ rexmpp_xml_t *jingle_ti =
+ rexmpp_xml_new_elem("jingle", "urn:xmpp:jingle:1");
+ rexmpp_xml_add_attr(jingle_ti, "sid", sess->sid);
+ rexmpp_xml_add_attr(jingle_ti, "action", "transport-info");
+ rexmpp_xml_t *content_copy = rexmpp_xml_clone(content);
+ rexmpp_xml_t *transport_copy = rexmpp_xml_clone(transport);
+ rexmpp_xml_add_child(jingle_ti, content_copy);
+ rexmpp_xml_add_child(content_copy, transport_copy);
+ rexmpp_xml_add_child(transport_copy, candidate);
jingle_ti->next = postponed_candidates;
postponed_candidates = jingle_ti;
}
@@ -936,24 +935,24 @@ rexmpp_jingle_candidate_gathering_done_cb (NiceAgent *agent,
}
}
- xmlNodePtr fingerprint =
- rexmpp_xml_new_node("fingerprint", "urn:xmpp:jingle:apps:dtls:0");
- xmlNewProp(fingerprint, "hash", "sha-256");
+ rexmpp_xml_t *fingerprint =
+ rexmpp_xml_new_elem("fingerprint", "urn:xmpp:jingle:apps:dtls:0");
+ rexmpp_xml_add_attr(fingerprint, "hash", "sha-256");
if (sess->initiator) {
- xmlNewProp(fingerprint, "setup", "actpass");
+ rexmpp_xml_add_attr(fingerprint, "setup", "actpass");
} else if (rexmpp_jingle_dtls_is_active(sess, 1)) {
- xmlNewProp(fingerprint, "setup", "active");
+ rexmpp_xml_add_attr(fingerprint, "setup", "active");
} else {
- xmlNewProp(fingerprint, "setup", "passive");
+ rexmpp_xml_add_attr(fingerprint, "setup", "passive");
}
- xmlNodeAddContent(fingerprint, fp_str);
- xmlAddChild(transport, fingerprint);
+ rexmpp_xml_add_text(fingerprint, fp_str);
+ rexmpp_xml_add_child(transport, fingerprint);
if (sess->initiator) {
- sess->initiate = xmlCopyNode(jingle, 1);
+ sess->initiate = rexmpp_xml_clone(jingle);
} else {
- sess->accept = xmlCopyNode(jingle, 1);
+ sess->accept = rexmpp_xml_clone(jingle);
}
rexmpp_iq_new(sess->s, "set", sess->jid, jingle,
@@ -962,7 +961,7 @@ rexmpp_jingle_candidate_gathering_done_cb (NiceAgent *agent,
/* Now send transport-info messages with candidates that didn't fit
initially. */
while (postponed_candidates != NULL) {
- xmlNodePtr pc_next = postponed_candidates->next;
+ rexmpp_xml_t *pc_next = postponed_candidates->next;
postponed_candidates->next = NULL;
rexmpp_iq_new(sess->s, "set", sess->jid, postponed_candidates,
rexmpp_transport_info_call_cb, strdup(sess->sid));
@@ -1060,7 +1059,7 @@ rexmpp_jingle_dtls_generic_pull_timeout_func (rexmpp_jingle_session_t *sess,
recvfrom(fd, &c, 1, MSG_PEEK,
(struct sockaddr *) &cli_addr, &cli_addr_size);
if (ret > 0) {
- return 1;
+ return 1;
}
return 0;
@@ -1306,25 +1305,25 @@ void rexmpp_jingle_stun_dns_cb (rexmpp_t *s, void *ptr, rexmpp_dns_result_t *res
void rexmpp_jingle_turn_cb (rexmpp_t *s,
void *sess_ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)req;
rexmpp_jingle_session_t *sess = sess_ptr;
if (success) {
/* use credentials */
- xmlNodePtr services = xmlFirstElementChild(response);
+ rexmpp_xml_t *services = rexmpp_xml_first_elem_child(response);
if (rexmpp_xml_match(services, "urn:xmpp:extdisco:2", "services")) {
- xmlNodePtr service = xmlFirstElementChild(services);
+ rexmpp_xml_t *service = rexmpp_xml_first_elem_child(services);
while (service != NULL) {
if (rexmpp_xml_match(service, "urn:xmpp:extdisco:2", "service")) {
- char *type = xmlGetProp(service, "type");
- char *transport = xmlGetProp(service, "transport");
- char *host = xmlGetProp(service, "host");
- char *port = xmlGetProp(service, "port");
- char *username = xmlGetProp(service, "username");
- char *password = xmlGetProp(service, "password");
+ const char *type = rexmpp_xml_find_attr_val(service, "type");
+ const char *transport = rexmpp_xml_find_attr_val(service, "transport");
+ const char *host = rexmpp_xml_find_attr_val(service, "host");
+ const char *port = rexmpp_xml_find_attr_val(service, "port");
+ const char *username = rexmpp_xml_find_attr_val(service, "username");
+ const char *password = rexmpp_xml_find_attr_val(service, "password");
if (sess->stun_host == NULL &&
type != NULL && transport != NULL && host != NULL && port != NULL &&
@@ -1344,27 +1343,8 @@ void rexmpp_jingle_turn_cb (rexmpp_t *s,
sess->turn_password = strdup(password);
rexmpp_log(s, LOG_DEBUG, "Setting TURN server to %s:%s", host, port);
}
-
- if (type != NULL) {
- free(type);
- }
- if (transport != NULL) {
- free(transport);
- }
- if (host != NULL) {
- free(host);
- }
- if (port != NULL) {
- free(port);
- }
- if (username != NULL) {
- free(username);
- }
- if (password != NULL) {
- free(password);
- }
}
- service = service->next;
+ service = rexmpp_xml_next_elem_sibling(service);
}
if (sess->stun_host != NULL) {
/* Resolve, then resolve STUN host, then connect. */
@@ -1392,25 +1372,24 @@ void rexmpp_jingle_turn_cb (rexmpp_t *s,
void rexmpp_jingle_discover_turn_cb (rexmpp_t *s,
void *sess_ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)req;
- char *response_from = xmlGetProp(response, "from");
+ const char *response_from = rexmpp_xml_find_attr_val(response, "from");
rexmpp_jingle_session_t *sess = sess_ptr;
if (success) {
- xmlNodePtr services = rexmpp_xml_new_node("services", "urn:xmpp:extdisco:2");
- xmlNewProp(services, "type", "turn");
- rexmpp_iq_new(s, "get", response_from, services, rexmpp_jingle_turn_cb, sess_ptr);
+ rexmpp_xml_t *services =
+ rexmpp_xml_new_elem("services", "urn:xmpp:extdisco:2");
+ rexmpp_xml_add_attr(services, "type", "turn");
+ rexmpp_iq_new(s, "get", response_from, services,
+ rexmpp_jingle_turn_cb, sess_ptr);
} else {
rexmpp_log(s, LOG_DEBUG,
"No external service discovery, trying to connect without STUN/TURN");
nice_agent_gather_candidates(sess->ice_agent, sess->ice_stream_id);
}
- if (response_from != NULL) {
- free(response_from);
- }
}
void rexmpp_jingle_discover_turn (rexmpp_t *s, rexmpp_jingle_session_t *sess) {
@@ -1446,11 +1425,11 @@ rexmpp_jingle_call_accept (rexmpp_t *s,
rexmpp_jingle_ice_agent_init(sess);
rexmpp_jingle_bind_sockets(sess, rtp_port_in, rtp_port_out);
- xmlNodePtr content =
+ rexmpp_xml_t *content =
rexmpp_xml_find_child(sess->initiate,
"urn:xmpp:jingle:1",
"content");
- xmlNodePtr ice_udp_transport =
+ rexmpp_xml_t * ice_udp_transport =
rexmpp_xml_find_child(content,
"urn:xmpp:jingle:transports:ice-udp:1",
"transport");
@@ -1458,7 +1437,7 @@ rexmpp_jingle_call_accept (rexmpp_t *s,
rexmpp_log(s, LOG_ERR, "No ICE-UDP transport defined for session %s", sid);
rexmpp_jingle_session_terminate
(s, sid,
- rexmpp_xml_new_node("unsupported-transports", "urn:xmpp:jingle:1"),
+ rexmpp_xml_new_elem("unsupported-transports", "urn:xmpp:jingle:1"),
"No ICE-UDP transport defined");
return REXMPP_E_OTHER;
}
@@ -1495,42 +1474,44 @@ rexmpp_jingle_call_accept (rexmpp_t *s,
}
#endif
-int rexmpp_jingle_iq (rexmpp_t *s, xmlNodePtr elem) {
+int rexmpp_jingle_iq (rexmpp_t *s, rexmpp_xml_t *elem) {
int handled = 0;
if (! s->enable_jingle) {
return handled;
}
- xmlNodePtr jingle = rexmpp_xml_find_child(elem, "urn:xmpp:jingle:1", "jingle");
+ rexmpp_xml_t *jingle =
+ rexmpp_xml_find_child(elem, "urn:xmpp:jingle:1", "jingle");
if (jingle != NULL) {
handled = 1;
- char *action = xmlGetProp(jingle, "action");
- char *sid = xmlGetProp(jingle, "sid");
- char *from_jid = xmlGetProp(elem, "from");
+ const char *action = rexmpp_xml_find_attr_val(jingle, "action");
+ const char *sid = rexmpp_xml_find_attr_val(jingle, "sid");
+ const char *from_jid = rexmpp_xml_find_attr_val(elem, "from");
if (action != NULL && sid != NULL && from_jid != NULL) {
if (strcmp(action, "session-initiate") == 0) {
/* todo: could be more than one content element, handle that */
- xmlNodePtr content =
+ rexmpp_xml_t *content =
rexmpp_xml_find_child(jingle, "urn:xmpp:jingle:1", "content");
if (content == NULL) {
- rexmpp_iq_reply(s, elem, "error", rexmpp_xml_error("cancel", "bad-request"));
+ rexmpp_iq_reply(s, elem, "error",
+ rexmpp_xml_error("cancel", "bad-request"));
} else {
rexmpp_iq_reply(s, elem, "result", NULL);
- xmlNodePtr file_description =
+ rexmpp_xml_t *file_description =
rexmpp_xml_find_child(content, "urn:xmpp:jingle:apps:file-transfer:5",
"description");
- xmlNodePtr ibb_transport =
+ rexmpp_xml_t *ibb_transport =
rexmpp_xml_find_child(content, "urn:xmpp:jingle:transports:ibb:1",
"transport");
- xmlNodePtr ice_udp_transport =
+ rexmpp_xml_t *ice_udp_transport =
rexmpp_xml_find_child(content, "urn:xmpp:jingle:transports:ice-udp:1",
"transport");
- xmlNodePtr rtp_description =
+ rexmpp_xml_t *rtp_description =
rexmpp_xml_find_child(content, "urn:xmpp:jingle:apps:rtp:1",
"description");
if (file_description != NULL && ibb_transport != NULL) {
- char *ibb_sid = xmlGetProp(ibb_transport, "sid");
+ char *ibb_sid = strdup(rexmpp_xml_find_attr_val(ibb_transport, "sid"));
if (ibb_sid != NULL) {
rexmpp_log(s, LOG_DEBUG,
"Jingle session-initiate from %s, sid %s, ibb sid %s",
@@ -1539,11 +1520,11 @@ int rexmpp_jingle_iq (rexmpp_t *s, xmlNodePtr elem) {
rexmpp_jingle_session_create(s, strdup(from_jid), strdup(sid),
REXMPP_JINGLE_SESSION_FILE, 0);
if (sess != NULL) {
- sess->initiate = xmlCopyNode(jingle, 1);
+ sess->initiate = rexmpp_xml_clone(jingle);
sess->ibb_sid = ibb_sid;
} else {
rexmpp_jingle_session_terminate(s, sid,
- rexmpp_xml_new_node("failed-transport",
+ rexmpp_xml_new_elem("failed-transport",
"urn:xmpp:jingle:1"),
NULL);
}
@@ -1551,7 +1532,7 @@ int rexmpp_jingle_iq (rexmpp_t *s, xmlNodePtr elem) {
rexmpp_log(s, LOG_ERR, "Jingle IBB transport doesn't have a sid attribute");
rexmpp_jingle_session_terminate
(s, sid,
- rexmpp_xml_new_node("unsupported-transports",
+ rexmpp_xml_new_elem("unsupported-transports",
"urn:xmpp:jingle:1"),
NULL);
}
@@ -1566,19 +1547,19 @@ int rexmpp_jingle_iq (rexmpp_t *s, xmlNodePtr elem) {
(rexmpp_xml_find_child(rtp_description,
"urn:xmpp:jingle:apps:rtp:1",
"rtcp-mux") != NULL);
- sess->initiate = xmlCopyNode(jingle, 1);
+ sess->initiate = rexmpp_xml_clone(jingle);
#endif
} else if (file_description == NULL &&
rtp_description == NULL) {
rexmpp_jingle_session_terminate
(s, sid,
- rexmpp_xml_new_node("unsupported-applications",
+ rexmpp_xml_new_elem("unsupported-applications",
"urn:xmpp:jingle:1"),
NULL);
} else if (ibb_transport == NULL &&
ice_udp_transport == NULL) {
rexmpp_jingle_session_terminate(s, sid,
- rexmpp_xml_new_node("unsupported-transports",
+ rexmpp_xml_new_elem("unsupported-transports",
"urn:xmpp:jingle:1"),
NULL);
} else {
@@ -1593,26 +1574,26 @@ int rexmpp_jingle_iq (rexmpp_t *s, xmlNodePtr elem) {
rexmpp_iq_reply(s, elem, "result", NULL);
rexmpp_jingle_session_t *session = rexmpp_jingle_session_by_id(s, sid);
if (session != NULL) {
- session->accept = xmlCopyNode(jingle, 1);
- xmlNodePtr content =
+ session->accept = rexmpp_xml_clone(jingle);
+ rexmpp_xml_t *content =
rexmpp_xml_find_child(jingle, "urn:xmpp:jingle:1", "content");
- xmlNodePtr file_description =
+ rexmpp_xml_t *file_description =
rexmpp_xml_find_child(content, "urn:xmpp:jingle:apps:file-transfer:5",
"description");
- xmlNodePtr ibb_transport =
+ rexmpp_xml_t *ibb_transport =
rexmpp_xml_find_child(content, "urn:xmpp:jingle:transports:ibb:1",
"transport");
if (ibb_transport != NULL && file_description != NULL) {
- xmlNodePtr open =
- rexmpp_xml_new_node("open", "http://jabber.org/protocol/ibb");
- xmlNewProp(open, "sid", session->ibb_sid);
- xmlNewProp(open, "block-size", "4096");
- xmlNewProp(open, "stanza", "iq");
+ rexmpp_xml_t *open =
+ rexmpp_xml_new_elem("open", "http://jabber.org/protocol/ibb");
+ rexmpp_xml_add_attr(open, "sid", session->ibb_sid);
+ rexmpp_xml_add_attr(open, "block-size", "4096");
+ rexmpp_xml_add_attr(open, "stanza", "iq");
rexmpp_iq_new(s, "set", session->jid, open,
rexmpp_jingle_ibb_send_cb, strdup(sid));
} else {
#ifdef ENABLE_CALLS
- xmlNodePtr ice_udp_transport =
+ rexmpp_xml_t *ice_udp_transport =
rexmpp_xml_find_child(content, "urn:xmpp:jingle:transports:ice-udp:1",
"transport");
if (ice_udp_transport != NULL) {
@@ -1626,9 +1607,9 @@ int rexmpp_jingle_iq (rexmpp_t *s, xmlNodePtr elem) {
rexmpp_jingle_session_t *session = rexmpp_jingle_session_by_id(s, sid);
if (session != NULL) {
#ifdef ENABLE_CALLS
- xmlNodePtr content =
+ rexmpp_xml_t *content =
rexmpp_xml_find_child(jingle, "urn:xmpp:jingle:1", "content");
- xmlNodePtr ice_udp_transport =
+ rexmpp_xml_t *ice_udp_transport =
rexmpp_xml_find_child(content, "urn:xmpp:jingle:transports:ice-udp:1",
"transport");
if (ice_udp_transport != NULL) {
@@ -1638,62 +1619,54 @@ int rexmpp_jingle_iq (rexmpp_t *s, xmlNodePtr elem) {
}
} else {
rexmpp_log(s, LOG_WARNING, "Unknown Jingle action: %s", action);
- rexmpp_iq_reply(s, elem, "error", rexmpp_xml_error("cancel", "bad-request"));
+ rexmpp_iq_reply(s, elem, "error",
+ rexmpp_xml_error("cancel", "bad-request"));
}
} else {
rexmpp_log(s, LOG_WARNING, "Received a malformed Jingle element");
- rexmpp_iq_reply(s, elem, "error", rexmpp_xml_error("cancel", "bad-request"));
- }
- if (action != NULL) {
- free(action);
- }
- if (sid != NULL) {
- free(sid);
- }
- if (from_jid != NULL) {
- free(from_jid);
+ rexmpp_iq_reply(s, elem, "error",
+ rexmpp_xml_error("cancel", "bad-request"));
}
}
/* XEP-0261: Jingle In-Band Bytestreams Transport Method */
- xmlNodePtr ibb_open =
+ rexmpp_xml_t *ibb_open =
rexmpp_xml_find_child(elem, "http://jabber.org/protocol/ibb", "open");
if (ibb_open != NULL) {
handled = 1;
/* no-op, though could check sid here. */
rexmpp_iq_reply(s, elem, "result", NULL);
}
- xmlNodePtr ibb_close =
+ rexmpp_xml_t *ibb_close =
rexmpp_xml_find_child(elem, "http://jabber.org/protocol/ibb", "close");
if (ibb_close != NULL) {
handled = 1;
rexmpp_iq_reply(s, elem, "result", NULL);
- char *sid = xmlGetProp(ibb_close, "sid");
+ const char *sid = rexmpp_xml_find_attr_val(ibb_close, "sid");
if (sid != NULL) {
rexmpp_jingle_session_t *session = rexmpp_jingle_session_by_ibb_sid(s, sid);
if (session != NULL) {
rexmpp_jingle_session_terminate
(s, session->sid,
- rexmpp_xml_new_node("success", "urn:xmpp:jingle:1"), NULL);
+ rexmpp_xml_new_elem("success", "urn:xmpp:jingle:1"), NULL);
}
- free(sid);
}
}
- xmlNodePtr ibb_data =
+ rexmpp_xml_t *ibb_data =
rexmpp_xml_find_child(elem, "http://jabber.org/protocol/ibb", "data");
if (ibb_data != NULL) {
handled = 1;
- char *sid = xmlGetProp(ibb_data, "sid");
+ const char *sid = rexmpp_xml_find_attr_val(ibb_data, "sid");
if (sid != NULL) {
rexmpp_jingle_session_t *session = rexmpp_jingle_session_by_ibb_sid(s, sid);
if (session != NULL && session->ibb_fh != NULL) {
- char *data = NULL, *data_base64 = xmlNodeGetContent(ibb_data);
+ char *data = NULL;
+ const char *data_base64 = rexmpp_xml_text_child(ibb_data);
if (data_base64 != NULL) {
size_t data_len = 0;
int base64_err = rexmpp_base64_from(data_base64, strlen(data_base64),
- &data, &data_len);
- free(data_base64);
+ &data, &data_len);
if (base64_err != 0) {
rexmpp_log(s, LOG_ERR, "Base-64 decoding failure");
} else {
@@ -1706,7 +1679,6 @@ int rexmpp_jingle_iq (rexmpp_t *s, xmlNodePtr elem) {
}
}
}
- free(sid);
}
/* todo: report errors */
rexmpp_iq_reply(s, elem, "result", NULL);
@@ -1872,13 +1844,13 @@ rexmpp_jingle_run (rexmpp_t *s,
cert_list_size);
rexmpp_jingle_session_terminate
(s, sess->sid,
- rexmpp_xml_new_node("security-error", "urn:xmpp:jingle:1"),
+ rexmpp_xml_new_elem("security-error", "urn:xmpp:jingle:1"),
"Unexpected certificate list size; expected exactly 1.");
} else {
- xmlNodePtr jingle = comp->session->initiator
+ rexmpp_xml_t *jingle = comp->session->initiator
? comp->session->accept
: comp->session->initiate;
- xmlNodePtr fingerprint =
+ rexmpp_xml_t *fingerprint =
rexmpp_xml_find_child
(rexmpp_xml_find_child
(rexmpp_xml_find_child
@@ -1892,16 +1864,16 @@ rexmpp_jingle_run (rexmpp_t *s,
"No fingerprint in the peer's Jingle element");
rexmpp_jingle_session_terminate
(s, sess->sid,
- rexmpp_xml_new_node("connectivity-error", "urn:xmpp:jingle:1"),
+ rexmpp_xml_new_elem("connectivity-error", "urn:xmpp:jingle:1"),
"No fingerprint element");
} else {
- char *hash_str = xmlGetProp(fingerprint, "hash");
+ const char *hash_str = rexmpp_xml_find_attr_val(fingerprint, "hash");
if (hash_str == NULL) {
rexmpp_log(comp->s, LOG_ERR,
"No hash attribute in the peer's fingerprint element");
rexmpp_jingle_session_terminate
(s, sess->sid,
- rexmpp_xml_new_node("connectivity-error", "urn:xmpp:jingle:1"),
+ rexmpp_xml_new_elem("connectivity-error", "urn:xmpp:jingle:1"),
"No hash attribute in the fingerprint element");
break;
} else {
@@ -1922,13 +1894,12 @@ rexmpp_jingle_run (rexmpp_t *s,
} else if (strcmp(hash_str, "md5") == 0) {
algo = GNUTLS_DIG_MD5;
}
- free(hash_str);
if (algo == GNUTLS_DIG_UNKNOWN) {
rexmpp_log(comp->s, LOG_ERR,
"Unknown hash algorithm in the peer's fingerprint");
rexmpp_jingle_session_terminate
(s, sess->sid,
- rexmpp_xml_new_node("connectivity-error", "urn:xmpp:jingle:1"),
+ rexmpp_xml_new_elem("connectivity-error", "urn:xmpp:jingle:1"),
"Unknown hash algorithm for a DTLS certificate fingerprint");
break;
} else {
@@ -1942,19 +1913,19 @@ rexmpp_jingle_run (rexmpp_t *s,
}
fp_str[fp_size * 3 - 1] = 0;
- char *fingerprint_cont = xmlNodeGetContent(fingerprint);
+ const char *fingerprint_cont =
+ rexmpp_xml_text_child(fingerprint);
/* Fingerprint string should be uppercase, but
allowing any case for now, while Dino uses
lowercase. */
int fingerprint_mismatch = strcasecmp(fingerprint_cont, fp_str);
- free(fingerprint_cont);
if (fingerprint_mismatch) {
rexmpp_log(comp->s, LOG_ERR,
"Peer's fingerprint mismatch: expected %s, calculated %s",
fingerprint_cont, fp_str);
rexmpp_jingle_session_terminate
(s, sess->sid,
- rexmpp_xml_new_node("security-error", "urn:xmpp:jingle:1"),
+ rexmpp_xml_new_elem("security-error", "urn:xmpp:jingle:1"),
"DTLS certificate fingerprint mismatch");
break;
} else {
@@ -2019,7 +1990,7 @@ rexmpp_jingle_run (rexmpp_t *s,
if (comp->component_id == 1) {
rexmpp_jingle_session_terminate
(s, sess->sid,
- rexmpp_xml_new_node("connectivity-error", "urn:xmpp:jingle:1"),
+ rexmpp_xml_new_elem("connectivity-error", "urn:xmpp:jingle:1"),
"DTLS connection error");
break;
}
diff --git a/src/rexmpp_jingle.h b/src/rexmpp_jingle.h
index d3e11eb..eb0a0d3 100644
--- a/src/rexmpp_jingle.h
+++ b/src/rexmpp_jingle.h
@@ -24,7 +24,7 @@
#include "rexmpp.h"
/** @brief Processes incoming Jingle IQs. */
-int rexmpp_jingle_iq (rexmpp_t *s, xmlNodePtr elem);
+int rexmpp_jingle_iq (rexmpp_t *s, rexmpp_xml_t *elem);
/** @brief Destroys Jingle sessions. */
void rexmpp_jingle_stop (rexmpp_t *s);
@@ -45,7 +45,7 @@ rexmpp_jingle_send_file (rexmpp_t *s,
rexmpp_err_t
rexmpp_jingle_session_terminate (rexmpp_t *s,
const char *sid,
- xmlNodePtr reason_node,
+ rexmpp_xml_t *reason_node,
const char *reason_text);
typedef struct rexmpp_jingle_component rexmpp_jingle_component_t;
@@ -79,8 +79,8 @@ struct rexmpp_jingle_component {
struct rexmpp_jingle_session {
char *jid;
char *sid;
- xmlNodePtr initiate;
- xmlNodePtr accept;
+ rexmpp_xml_t *initiate;
+ rexmpp_xml_t *accept;
rexmpp_jingle_session_t *next;
/* Sessions are commonly passed to callbacks by external libraries,
so it's convenient to have the corresponding rexmpp_t accessible
diff --git a/src/rexmpp_openpgp.c b/src/rexmpp_openpgp.c
index 13cee44..85ebc68 100644
--- a/src/rexmpp_openpgp.c
+++ b/src/rexmpp_openpgp.c
@@ -47,10 +47,10 @@ Possible future improvements:
#ifdef HAVE_GPGME
#include <gpgme.h>
#endif
-#include <libxml/tree.h>
#include <gcrypt.h>
#include "rexmpp.h"
+#include "rexmpp_xml.h"
#include "rexmpp_openpgp.h"
#include "rexmpp_jid.h"
#include "rexmpp_pubsub.h"
@@ -61,8 +61,8 @@ Possible future improvements:
void rexmpp_pgp_fp_reply (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
@@ -71,33 +71,33 @@ void rexmpp_pgp_fp_reply (rexmpp_t *s,
rexmpp_log(s, LOG_WARNING, "Failed to retrieve an OpenpPGP key");
return;
}
- xmlNodePtr pubsub =
+ rexmpp_xml_t *pubsub =
rexmpp_xml_find_child(response, "http://jabber.org/protocol/pubsub",
"pubsub");
if (pubsub == NULL) {
rexmpp_log(s, LOG_ERR, "OpenPGP key retrieval: not a pubsub response");
return;
}
- xmlNodePtr items =
- rexmpp_xml_find_child(pubsub, "http://jabber.org/protocol/pubsub",
- "items");
+ rexmpp_xml_t *items =
+ rexmpp_xml_find_child(pubsub, "http://jabber.org/protocol/pubsub",
+ "items");
if (items == NULL) {
rexmpp_log(s, LOG_ERR, "OpenPGP key retrieval: no items in pubsub element");
return;
}
- xmlNodePtr item =
+ rexmpp_xml_t *item =
rexmpp_xml_find_child(items, "http://jabber.org/protocol/pubsub", "item");
if (item == NULL) {
rexmpp_log(s, LOG_ERR, "OpenPGP key retrieval: no item in items");
return;
}
- xmlNodePtr pubkey =
+ rexmpp_xml_t *pubkey =
rexmpp_xml_find_child(item, "urn:xmpp:openpgp:0", "pubkey");
if (pubkey == NULL) {
rexmpp_log(s, LOG_ERR, "OpenPGP key retrieval: no pubkey in item");
return;
}
- xmlNodePtr data =
+ rexmpp_xml_t *data =
rexmpp_xml_find_child(pubkey, "urn:xmpp:openpgp:0", "data");
if (data == NULL) {
rexmpp_log(s, LOG_ERR, "OpenPGP key retrieval: no data in pubkey");
@@ -106,10 +106,9 @@ void rexmpp_pgp_fp_reply (rexmpp_t *s,
char *key_raw = NULL;
size_t key_raw_len = 0;
- char *key_base64 = xmlNodeGetContent(data);
+ const char *key_base64 = rexmpp_xml_text_child(data);
int base64_err =
rexmpp_base64_from(key_base64, strlen(key_base64), &key_raw, &key_raw_len);
- free(key_base64);
if (base64_err != 0) {
rexmpp_log(s, LOG_ERR, "Base-64 key decoding failure");
return;
@@ -140,18 +139,19 @@ void rexmpp_pgp_fp_reply (rexmpp_t *s,
rexmpp_err_t
rexmpp_openpgp_check_keys (rexmpp_t *s,
const char *jid,
- xmlNodePtr items)
+ rexmpp_xml_t *items)
{
- xmlNodePtr item =
+ rexmpp_xml_t *item =
rexmpp_xml_find_child(items, "http://jabber.org/protocol/pubsub#event",
"item");
- xmlNodePtr list =
- rexmpp_xml_find_child(item, "urn:xmpp:openpgp:0", "public-keys-list");
- xmlNodePtr metadata;
- for (metadata = xmlFirstElementChild(list);
+ rexmpp_xml_t *list =
+ rexmpp_xml_find_child(item, "urn:xmpp:openpgp:0", "public-keys-list");
+ rexmpp_xml_t *metadata;
+ for (metadata = rexmpp_xml_first_elem_child(list);
metadata != NULL;
- metadata = xmlNextElementSibling(metadata)) {
- char *fingerprint = xmlGetProp(metadata, "v4-fingerprint");
+ metadata = rexmpp_xml_next_elem_sibling(metadata)) {
+ const char *fingerprint =
+ rexmpp_xml_find_attr_val(metadata, "v4-fingerprint");
gpgme_key_t key;
gpgme_error_t err;
err = gpgme_get_key(s->pgp_ctx, fingerprint, &key, 0);
@@ -162,97 +162,95 @@ rexmpp_openpgp_check_keys (rexmpp_t *s,
rexmpp_log(s, LOG_DEBUG,
"Unknown OpenPGP key fingerprint for %s: %s",
jid, fingerprint);
- xmlNodePtr fp_req = xmlNewNode(NULL, "pubsub");
- xmlNewNs(fp_req, "http://jabber.org/protocol/pubsub", NULL);
- xmlNodePtr fp_req_items = xmlNewNode(NULL, "items");
- xmlNewProp(fp_req_items, "max_items", "1");
+ rexmpp_xml_t *fp_req =
+ rexmpp_xml_new_elem("pubsub", "http://jabber.org/protocol/pubsub");
+ rexmpp_xml_t *fp_req_items =
+ rexmpp_xml_new_elem("items", NULL);
+ rexmpp_xml_add_attr(fp_req_items, "max_items", "1");
char key_node[72];
snprintf(key_node, 72, "urn:xmpp:openpgp:0:public-keys:%s", fingerprint);
- xmlNewProp(fp_req_items, "node", key_node);
- xmlAddChild(fp_req, fp_req_items);
+ rexmpp_xml_add_attr(fp_req_items, "node", key_node);
+ rexmpp_xml_add_child(fp_req, fp_req_items);
rexmpp_iq_new(s, "get", jid, fp_req, rexmpp_pgp_fp_reply, NULL);
} else if (gpg_err_code(err) != GPG_ERR_NO_ERROR) {
rexmpp_log(s, LOG_WARNING,
"OpenPGP error when looking for a key: %s",
gpgme_strerror(err));
}
- free(fingerprint);
}
return REXMPP_SUCCESS;
}
-xmlNodePtr rexmpp_published_fingerprints (rexmpp_t *s, const char *jid) {
- xmlNodePtr published =
+rexmpp_xml_t *rexmpp_published_fingerprints (rexmpp_t *s, const char *jid) {
+ rexmpp_xml_t *published =
rexmpp_find_event(s, jid, "urn:xmpp:openpgp:0:public-keys", NULL);
if (published == NULL) {
return NULL;
}
- xmlNodePtr event =
+ rexmpp_xml_t *event =
rexmpp_xml_find_child(published, "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");
- xmlNodePtr list =
+ rexmpp_xml_t *list =
rexmpp_xml_find_child(item, "urn:xmpp:openpgp:0",
"public-keys-list");
- xmlNodePtr published_fps = xmlFirstElementChild(list);
+ rexmpp_xml_t *published_fps = list->alt.elem.children;
return published_fps;
}
int rexmpp_openpgp_key_is_published (rexmpp_t *s, const char *fp) {
- xmlNodePtr metadata;
+ rexmpp_xml_t *metadata;
for (metadata = rexmpp_published_fingerprints(s, s->assigned_jid.bare);
metadata != NULL;
- metadata = xmlNextElementSibling(metadata)) {
+ metadata = metadata->next) {
if (! rexmpp_xml_match(metadata, "urn:xmpp:openpgp:0", "pubkey-metadata")) {
continue;
}
- char *fingerprint = xmlGetProp(metadata, "v4-fingerprint");
+ const char *fingerprint = rexmpp_xml_find_attr_val(metadata, "v4-fingerprint");
if (fingerprint == NULL) {
rexmpp_log(s, LOG_WARNING, "No fingerprint found in pubkey-metadata");
continue;
}
- int matches = (strcmp(fingerprint, fp) == 0);
- free(fingerprint);
- if (matches) {
+ if (strcmp(fingerprint, fp) == 0) {
return 1;
}
}
return 0;
}
-xmlNodePtr
+rexmpp_xml_t *
rexmpp_openpgp_remove_key_from_list (rexmpp_t *s,
const char *fp)
{
- xmlNodePtr fps =
- xmlCopyNodeList(rexmpp_published_fingerprints(s, s->assigned_jid.bare));
- xmlNodePtr metadata, prev = NULL;
+ rexmpp_xml_t *fps =
+ rexmpp_xml_clone_list(rexmpp_published_fingerprints(s, s->assigned_jid.bare));
+ rexmpp_xml_t *metadata, *prev = NULL;
for (metadata = fps;
metadata != NULL;
- prev = metadata, metadata = xmlNextElementSibling(metadata)) {
+ prev = metadata, metadata = rexmpp_xml_next_elem_sibling(metadata)) {
if (! rexmpp_xml_match(metadata, "urn:xmpp:openpgp:0", "pubkey-metadata")) {
continue;
}
- char *fingerprint = xmlGetProp(metadata, "v4-fingerprint");
+ const char *fingerprint =
+ rexmpp_xml_find_attr_val(metadata, "v4-fingerprint");
if (fingerprint == NULL) {
rexmpp_log(s, LOG_WARNING, "No fingerprint found in pubkey-metadata");
continue;
}
int matches = (strcmp(fingerprint, fp) == 0);
- free(fingerprint);
if (matches) {
if (prev != NULL) {
prev->next = metadata->next;
} else {
fps = metadata->next;
}
- xmlFreeNode(metadata);
+ rexmpp_xml_free(metadata);
return fps;
}
}
@@ -261,8 +259,8 @@ rexmpp_openpgp_remove_key_from_list (rexmpp_t *s,
void rexmpp_pgp_key_publish_list_iq (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
@@ -275,18 +273,18 @@ void rexmpp_pgp_key_publish_list_iq (rexmpp_t *s,
rexmpp_log(s, LOG_INFO, "Published an OpenpPGP key list");
}
-void rexmpp_pgp_key_fp_list_upload (rexmpp_t *s, xmlNodePtr metadata) {
- xmlNodePtr keylist = xmlNewNode(NULL, "public-keys-list");
- xmlNewNs(keylist, "urn:xmpp:openpgp:0", NULL);
- xmlAddChild(keylist, metadata);
+void rexmpp_pgp_key_fp_list_upload (rexmpp_t *s, rexmpp_xml_t *metadata) {
+ rexmpp_xml_t *keylist =
+ rexmpp_xml_new_elem("public-keys-list", "urn:xmpp:openpgp:0");
+ rexmpp_xml_add_child(keylist, metadata);
rexmpp_pubsub_item_publish(s, NULL, "urn:xmpp:openpgp:0:public-keys",
NULL, keylist, rexmpp_pgp_key_publish_list_iq, NULL);
}
void rexmpp_pgp_key_delete_iq (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
@@ -295,18 +293,17 @@ void rexmpp_pgp_key_delete_iq (rexmpp_t *s,
rexmpp_log(s, LOG_WARNING, "Failed to delete an OpenpPGP key");
return;
}
- xmlNodePtr pubsub = xmlFirstElementChild(req);
- xmlNodePtr publish = xmlFirstElementChild(pubsub);
- char *node = xmlGetProp(publish, "node");
- char *fingerprint = node + 31;
+ rexmpp_xml_t *pubsub = req->alt.elem.children;
+ rexmpp_xml_t *publish = pubsub->alt.elem.children;;
+ const char *node = rexmpp_xml_find_attr_val(publish, "node");
+ const char *fingerprint = node + 31;
rexmpp_log(s, LOG_INFO, "Removed OpenpPGP key %s", fingerprint);
- free(node);
}
void rexmpp_pgp_key_publish_iq (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
@@ -316,10 +313,10 @@ void rexmpp_pgp_key_publish_iq (rexmpp_t *s,
return;
}
rexmpp_log(s, LOG_INFO, "Uploaded an OpenpPGP key");
- xmlNodePtr pubsub = xmlFirstElementChild(req);
- xmlNodePtr publish = xmlFirstElementChild(pubsub);
- char *node = xmlGetProp(publish, "node");
- char *fingerprint = node + 31;
+ rexmpp_xml_t *pubsub = req->alt.elem.children;
+ rexmpp_xml_t *publish = pubsub->alt.elem.children;;
+ const char *node = rexmpp_xml_find_attr_val(publish, "node");
+ const char *fingerprint = node + 31;
char time_str[42];
time_t t = time(NULL);
@@ -327,22 +324,20 @@ void rexmpp_pgp_key_publish_iq (rexmpp_t *s,
gmtime_r(&t, &utc_time);
strftime(time_str, 42, "%FT%TZ", &utc_time);
- xmlNodePtr metadata = xmlNewNode(NULL, "pubkey-metadata");
- xmlNewNs(metadata, "urn:xmpp:openpgp:0", NULL);
- xmlNewProp(metadata, "date", time_str);
- xmlNewProp(metadata, "v4-fingerprint", fingerprint);
-
- free(node);
+ rexmpp_xml_t *metadata =
+ rexmpp_xml_new_elem("pubkey-metadata", "urn:xmpp:openpgp:0");
+ rexmpp_xml_add_attr(metadata, "date", time_str);
+ rexmpp_xml_add_attr(metadata, "v4-fingerprint", fingerprint);
- xmlNodePtr fps = rexmpp_openpgp_remove_key_from_list(s, fingerprint);
+ rexmpp_xml_t *fps = rexmpp_openpgp_remove_key_from_list(s, fingerprint);
if (fps != NULL) {
- metadata->next = xmlCopyNodeList(fps);
+ metadata->next = fps;
}
rexmpp_pgp_key_fp_list_upload(s, metadata);
}
void rexmpp_openpgp_retract_key (rexmpp_t *s, const char *fp) {
- xmlNodePtr new_fp_list = rexmpp_openpgp_remove_key_from_list(s, fp);
+ rexmpp_xml_t *new_fp_list = rexmpp_openpgp_remove_key_from_list(s, fp);
if (new_fp_list != NULL) {
rexmpp_pgp_key_fp_list_upload(s, new_fp_list);
}
@@ -382,14 +377,14 @@ rexmpp_err_t rexmpp_openpgp_publish_key (rexmpp_t *s, const char *fp) {
key_raw = gpgme_data_release_and_get_mem(key_dh, &key_raw_len);
rexmpp_base64_to(key_raw, key_raw_len, &key_base64, &key_base64_len);
free(key_raw);
- xmlNodePtr data = xmlNewNode(NULL, "data");
- xmlNewNs(data, "urn:xmpp:openpgp:0", NULL);
- xmlNodeAddContent(data, key_base64);
+ rexmpp_xml_t *data =
+ rexmpp_xml_new_elem("data", "urn:xmpp:openpgp:0");
+ rexmpp_xml_add_text(data, key_base64);
free(key_base64);
- xmlNodePtr pubkey = xmlNewNode(NULL, "pubkey");
- xmlNewNs(pubkey, "urn:xmpp:openpgp:0", NULL);
- xmlAddChild(pubkey, data);
+ rexmpp_xml_t *pubkey =
+ rexmpp_xml_new_elem("pubkey", "urn:xmpp:openpgp:0");
+ rexmpp_xml_add_child(pubkey, data);
char time_str[42];
time_t t = time(NULL);
@@ -421,9 +416,9 @@ int rexmpp_openpgp_fingerprint_matches (const char *f1, const char *f2) {
return 1;
}
-xmlNodePtr
+rexmpp_xml_t *
rexmpp_openpgp_decrypt_verify_message (rexmpp_t *s,
- xmlNodePtr message,
+ rexmpp_xml_t *message,
int *valid)
{
gpgme_error_t err;
@@ -433,14 +428,13 @@ rexmpp_openpgp_decrypt_verify_message (rexmpp_t *s,
rexmpp_log(s, LOG_ERR, "Not a message element");
return NULL;
}
- char *from_str = xmlGetProp(message, "from");
+ const char *from_str = rexmpp_xml_find_attr_val(message, "from");
if (from_str == NULL) {
rexmpp_log(s, LOG_ERR, "No 'from' attribute");
return NULL;
}
rexmpp_jid_parse(from_str, &from);
- free(from_str);
- char *to_str = xmlGetProp(message, "to");
+ const char *to_str = rexmpp_xml_find_attr_val(message, "to");
if (to_str == NULL) {
if (strcmp(from.bare, s->assigned_jid.bare) != 0) {
rexmpp_log(s, LOG_ERR, "No 'to' attribute");
@@ -449,18 +443,16 @@ rexmpp_openpgp_decrypt_verify_message (rexmpp_t *s,
rexmpp_jid_parse(from.full, &to);
} else {
rexmpp_jid_parse(to_str, &to);
- free(to_str);
}
- xmlNodePtr openpgp =
+ rexmpp_xml_t *openpgp =
rexmpp_xml_find_child(message, "urn:xmpp:openpgp:0", "openpgp");
if (openpgp == NULL) {
rexmpp_log(s, LOG_ERR, "No 'openpgp' child element");
return NULL;
}
- char *cipher_str = xmlNodeGetContent(openpgp);
- xmlNodePtr plain =
+ const char *cipher_str = rexmpp_xml_text_child(openpgp);
+ rexmpp_xml_t *plain =
rexmpp_openpgp_decrypt_verify(s, cipher_str);
- free(cipher_str);
if (plain == NULL) {
return NULL;
}
@@ -476,23 +468,20 @@ rexmpp_openpgp_decrypt_verify_message (rexmpp_t *s,
return plain;
}
- xmlNodePtr child;
+ rexmpp_xml_t *child;
int found = 0;
- for (child = xmlFirstElementChild(plain);
+ for (child = rexmpp_xml_first_elem_child(plain);
child != NULL && ! found;
- child = xmlNextElementSibling(child))
+ child = rexmpp_xml_next_elem_sibling(child))
{
if (rexmpp_xml_match(child, "urn:xmpp:openpgp:0", "to")) {
- char *to_jid = xmlGetProp(child, "jid");
+ const char *to_jid = rexmpp_xml_find_attr_val(child, "jid");
if (to_jid == NULL) {
rexmpp_log(s, LOG_WARNING,
"Found a 'to' element without a 'jid' attribute");
} else if (strcmp(to_jid, to.bare) == 0) {
found = 1;
}
- if (to_jid != NULL) {
- free(to_jid);
- }
}
}
if (! found) {
@@ -520,11 +509,11 @@ rexmpp_openpgp_decrypt_verify_message (rexmpp_t *s,
}
found = 0;
- xmlNodePtr metadata;
+ rexmpp_xml_t *metadata;
for (metadata = rexmpp_published_fingerprints(s, from.bare);
metadata != NULL && ! found;
- metadata = xmlNextElementSibling(metadata)) {
- char *fingerprint = xmlGetProp(metadata, "v4-fingerprint");
+ metadata = metadata->next) {
+ const char *fingerprint = rexmpp_xml_find_attr_val(metadata, "v4-fingerprint");
if (fingerprint == NULL) {
rexmpp_log(s, LOG_WARNING, "No fingerprint found in pubkey-metadata");
continue;
@@ -532,7 +521,6 @@ rexmpp_openpgp_decrypt_verify_message (rexmpp_t *s,
if (rexmpp_openpgp_fingerprint_matches(fingerprint, sig->fpr)) {
found = 1;
}
- free(fingerprint);
}
if (! found) {
rexmpp_log(s, LOG_ERR, "No %s's known key matches that of the signature",
@@ -570,7 +558,7 @@ rexmpp_openpgp_decrypt_verify_message (rexmpp_t *s,
return plain;
}
-xmlNodePtr
+rexmpp_xml_t *
rexmpp_openpgp_decrypt_verify (rexmpp_t *s,
const char *cipher_base64)
{
@@ -600,7 +588,7 @@ rexmpp_openpgp_decrypt_verify (rexmpp_t *s,
rexmpp_log(s, LOG_ERR, "Failed to release and get memory");
return NULL;
}
- xmlNodePtr elem = rexmpp_xml_parse(plain, plain_len);
+ rexmpp_xml_t *elem = rexmpp_xml_parse(plain, plain_len);
if(elem == NULL) {
rexmpp_log(s, LOG_ERR, "Failed to parse an XML document");
}
@@ -615,11 +603,11 @@ void rexmpp_openpgp_add_keys (rexmpp_t *s,
int *allocated)
{
gpgme_error_t err;
- xmlNodePtr metadata;
+ rexmpp_xml_t *metadata;
for (metadata = rexmpp_published_fingerprints(s, jid);
metadata != NULL;
- metadata = xmlNextElementSibling(metadata)) {
- char *fingerprint = xmlGetProp(metadata, "v4-fingerprint");
+ metadata = metadata->next) {
+ const char *fingerprint = rexmpp_xml_find_attr_val(metadata, "v4-fingerprint");
if (fingerprint == NULL) {
rexmpp_log(s, LOG_WARNING, "No fingerprint found in pubkey-metadata");
continue;
@@ -643,19 +631,18 @@ void rexmpp_openpgp_add_keys (rexmpp_t *s,
rexmpp_log(s, LOG_ERR, "Failed to read key %s: %s",
fingerprint, gpgme_strerror(err));
}
- free(fingerprint);
}
}
void rexmpp_openpgp_set_signers (rexmpp_t *s) {
gpgme_error_t err;
- xmlNodePtr metadata;
+ rexmpp_xml_t *metadata;
gpgme_key_t sec_key;
gpgme_signers_clear(s->pgp_ctx);
for (metadata = rexmpp_published_fingerprints(s, s->initial_jid.bare);
metadata != NULL;
- metadata = xmlNextElementSibling(metadata)) {
- char *fingerprint = xmlGetProp(metadata, "v4-fingerprint");
+ metadata = metadata->next) {
+ const char *fingerprint = rexmpp_xml_find_attr_val(metadata, "v4-fingerprint");
if (fingerprint == NULL) {
rexmpp_log(s, LOG_WARNING, "No fingerprint found in pubkey-metadata");
continue;
@@ -670,12 +657,11 @@ void rexmpp_openpgp_set_signers (rexmpp_t *s) {
rexmpp_log(s, LOG_ERR, "Failed to read key %s: %s",
fingerprint, gpgme_strerror(err));
}
- free(fingerprint);
}
}
char *rexmpp_openpgp_payload (rexmpp_t *s,
- xmlNodePtr payload,
+ rexmpp_xml_t *payload,
const char **recipients,
const char **signers,
enum rexmpp_ox_mode mode)
@@ -693,8 +679,8 @@ char *rexmpp_openpgp_payload (rexmpp_t *s,
} else if (mode == REXMPP_OX_CRYPT) {
elem_name = "crypt";
}
- xmlNodePtr elem = xmlNewNode(NULL, elem_name);
- xmlNewNs(elem, "urn:xmpp:openpgp:0", NULL);
+ rexmpp_xml_t *elem =
+ rexmpp_xml_new_elem(elem_name, "urn:xmpp:openpgp:0");
if (mode == REXMPP_OX_SIGN || mode == REXMPP_OX_SIGNCRYPT) {
if (signers == NULL) {
@@ -717,10 +703,10 @@ char *rexmpp_openpgp_payload (rexmpp_t *s,
/* Add all the recipients. */
for (i = 0; recipients[i] != NULL; i++) {
- xmlNodePtr to = xmlNewNode(NULL, "to");
- xmlNewNs(to, "urn:xmpp:openpgp:0", NULL);
- xmlNewProp(to, "jid", recipients[i]);
- xmlAddChild(elem, to);
+ rexmpp_xml_t *to =
+ rexmpp_xml_new_elem("to", "urn:xmpp:openpgp:0");
+ rexmpp_xml_add_attr(to, "jid", recipients[i]);
+ rexmpp_xml_add_child(elem, to);
}
}
@@ -730,16 +716,16 @@ char *rexmpp_openpgp_payload (rexmpp_t *s,
struct tm utc_time;
gmtime_r(&t, &utc_time);
strftime(time_str, 42, "%FT%TZ", &utc_time);
- xmlNodePtr time = xmlNewNode(NULL, "time");
- xmlNewNs(time, "urn:xmpp:openpgp:0", NULL);
- xmlNewProp(time, "stamp", time_str);
- xmlAddChild(elem, time);
+ rexmpp_xml_t *time =
+ rexmpp_xml_new_elem("time", "urn:xmpp:openpgp:0");
+ rexmpp_xml_add_attr(time, "stamp", time_str);
+ rexmpp_xml_add_child(elem, time);
/* Add the payload. */
- xmlNodePtr pl = xmlNewNode(NULL, "payload");
- xmlNewNs(pl, "urn:xmpp:openpgp:0", NULL);
- xmlAddChild(pl, payload);
- xmlAddChild(elem, pl);
+ rexmpp_xml_t *pl =
+ rexmpp_xml_new_elem("payload", "urn:xmpp:openpgp:0");
+ rexmpp_xml_add_child(pl, payload);
+ rexmpp_xml_add_child(elem, pl);
if (mode == REXMPP_OX_CRYPT || mode == REXMPP_OX_SIGNCRYPT) {
/* Add keys for encryption. */
@@ -758,16 +744,16 @@ char *rexmpp_openpgp_payload (rexmpp_t *s,
gcry_create_nonce(rand, rand_len);
rexmpp_base64_to(rand, rand_len, &rand_str, &rand_str_len);
- xmlNodePtr rpad = xmlNewNode(NULL, "rpad");
- xmlNewNs(rpad, "urn:xmpp:openpgp:0", NULL);
- xmlNodeAddContent(rpad, rand_str);
+ rexmpp_xml_t *rpad =
+ rexmpp_xml_new_elem("rpad", "urn:xmpp:openpgp:0");
+ rexmpp_xml_add_text(rpad, rand_str);
free(rand_str);
- xmlAddChild(elem, rpad);
+ rexmpp_xml_add_child(elem, rpad);
}
/* Serialize the resulting XML. */
char *plaintext = rexmpp_xml_serialize(elem);
- xmlFreeNode(elem);
+ rexmpp_xml_free(elem);
/* Encrypt, base64-encode. */
gpgme_data_t cipher_dh, plain_dh;
@@ -832,7 +818,7 @@ rexmpp_err_t gpgme_not_supported(rexmpp_t *s) {
rexmpp_err_t
rexmpp_openpgp_check_keys (rexmpp_t *s,
const char *jid,
- xmlNodePtr items) {
+ rexmpp_xml_t *items) {
(void)jid;
(void)items;
return gpgme_not_supported(s);
@@ -848,7 +834,7 @@ void rexmpp_openpgp_retract_key (rexmpp_t *s, const char *fp) {
gpgme_not_supported(s);
}
-xmlNodePtr
+rexmpp_xml_t *
rexmpp_openpgp_decrypt_verify (rexmpp_t *s,
const char *cipher_base64) {
(void)cipher_base64;
@@ -856,9 +842,9 @@ rexmpp_openpgp_decrypt_verify (rexmpp_t *s,
return NULL;
}
-xmlNodePtr
+rexmpp_xml_t *
rexmpp_openpgp_decrypt_verify_message (rexmpp_t *s,
- xmlNodePtr message,
+ rexmpp_xml_t *message,
int *valid) {
(void)message;
(void)valid;
@@ -867,7 +853,7 @@ rexmpp_openpgp_decrypt_verify_message (rexmpp_t *s,
}
char *rexmpp_openpgp_payload (rexmpp_t *s,
- xmlNodePtr payload,
+ rexmpp_xml_t *payload,
const char **recipients,
const char **signers,
enum rexmpp_ox_mode mode) {
diff --git a/src/rexmpp_openpgp.h b/src/rexmpp_openpgp.h
index 7470347..2132930 100644
--- a/src/rexmpp_openpgp.h
+++ b/src/rexmpp_openpgp.h
@@ -29,7 +29,7 @@ enum rexmpp_ox_mode {
rexmpp_err_t
rexmpp_openpgp_check_keys (rexmpp_t *s,
const char *jid,
- xmlNodePtr items);
+ rexmpp_xml_t *items);
/**
@brief Publishes a key via PEP/pubsub.
@@ -52,7 +52,7 @@ void rexmpp_openpgp_retract_key (rexmpp_t *s, const char *fp);
@param[in] cipher_base64 An OpenPGP ciphertext.
@returns A plaintext message body.
*/
-xmlNodePtr
+rexmpp_xml_t *
rexmpp_openpgp_decrypt_verify (rexmpp_t *s,
const char *cipher_base64);
@@ -65,9 +65,9 @@ rexmpp_openpgp_decrypt_verify (rexmpp_t *s,
valid.
@returns A decrypted message body.
*/
-xmlNodePtr
+rexmpp_xml_t *
rexmpp_openpgp_decrypt_verify_message (rexmpp_t *s,
- xmlNodePtr message,
+ rexmpp_xml_t *message,
int *valid);
/**
@@ -83,7 +83,7 @@ rexmpp_openpgp_decrypt_verify_message (rexmpp_t *s,
@returns An encoded <openpgp> payload.
*/
char *rexmpp_openpgp_payload (rexmpp_t *s,
- xmlNodePtr payload,
+ rexmpp_xml_t *payload,
const char **recipients,
const char **signers,
enum rexmpp_ox_mode mode);
diff --git a/src/rexmpp_pubsub.c b/src/rexmpp_pubsub.c
index 145a352..58cb060 100644
--- a/src/rexmpp_pubsub.c
+++ b/src/rexmpp_pubsub.c
@@ -7,25 +7,22 @@
*/
#include "rexmpp.h"
+#include "rexmpp_xml.h"
void
rexmpp_pubsub_iq (rexmpp_t *s,
const char *iq_type,
const char *pubsub_namespace,
const char *service_jid,
- xmlNodePtr payload,
+ rexmpp_xml_t *payload,
rexmpp_iq_callback_t callback,
void *cb_data)
{
- xmlNodePtr pubsub = xmlNewNode(NULL, "pubsub");
if (pubsub_namespace == NULL) {
- xmlNewNs(pubsub, "http://jabber.org/protocol/pubsub", NULL);
- } else {
- xmlNewNs(pubsub, pubsub_namespace, NULL);
+ pubsub_namespace = "http://jabber.org/protocol/pubsub";
}
-
- xmlAddChild(pubsub, payload);
-
+ rexmpp_xml_t *pubsub = rexmpp_xml_new_elem("pubsub", pubsub_namespace);
+ rexmpp_xml_add_child(pubsub, payload);
rexmpp_iq_new(s, iq_type, service_jid, pubsub, callback, cb_data);
}
@@ -34,21 +31,21 @@ rexmpp_pubsub_item_publish (rexmpp_t *s,
const char *service_jid,
const char *node,
const char *item_id,
- xmlNodePtr payload,
+ rexmpp_xml_t *payload,
rexmpp_iq_callback_t callback,
void *cb_data)
{
- xmlNodePtr item = xmlNewNode(NULL, "item");
- xmlNewNs(item, "http://jabber.org/protocol/pubsub", NULL);
+ rexmpp_xml_t *item =
+ rexmpp_xml_new_elem("item", "http://jabber.org/protocol/pubsub");
if (item_id != NULL) {
- xmlNewProp(item, "id", item_id);
+ rexmpp_xml_add_attr(item, "id", item_id);
}
- xmlAddChild(item, payload);
+ rexmpp_xml_add_child(item, payload);
- xmlNodePtr publish = xmlNewNode(NULL, "publish");
- xmlNewNs(publish, "http://jabber.org/protocol/pubsub", NULL);
- xmlNewProp(publish, "node", node);
- xmlAddChild(publish, item);
+ rexmpp_xml_t *publish =
+ rexmpp_xml_new_elem("publish", "http://jabber.org/protocol/pubsub");
+ rexmpp_xml_add_attr(publish, "node", node);
+ rexmpp_xml_add_child(publish, item);
rexmpp_pubsub_iq(s, "set", NULL, service_jid, publish, callback, cb_data);
}
@@ -61,16 +58,16 @@ rexmpp_pubsub_item_retract (rexmpp_t *s,
rexmpp_iq_callback_t callback,
void *cb_data)
{
- xmlNodePtr item = xmlNewNode(NULL, "item");
- xmlNewNs(item, "http://jabber.org/protocol/pubsub", NULL);
+ rexmpp_xml_t *item =
+ rexmpp_xml_new_elem("item", "http://jabber.org/protocol/pubsub");
if (item_id != NULL) {
- xmlNewProp(item, "id", item_id);
+ rexmpp_xml_add_attr(item, "id", item_id);
}
- xmlNodePtr retract = xmlNewNode(NULL, "retract");
- xmlNewNs(retract, "http://jabber.org/protocol/pubsub", NULL);
- xmlNewProp(retract, "node", node);
- xmlAddChild(retract, item);
+ rexmpp_xml_t *retract =
+ rexmpp_xml_new_elem("retract", "http://jabber.org/protocol/pubsub");
+ rexmpp_xml_add_attr(retract, "node", node);
+ rexmpp_xml_add_child(retract, item);
rexmpp_pubsub_iq(s, "set", NULL, service_jid, retract, callback, cb_data);
}
@@ -82,9 +79,9 @@ rexmpp_pubsub_node_delete (rexmpp_t *s,
rexmpp_iq_callback_t callback,
void *cb_data)
{
- xmlNodePtr delete = xmlNewNode(NULL, "delete");
- xmlNewNs(delete, "http://jabber.org/protocol/pubsub#owner", NULL);
- xmlNewProp(delete, "node", node);
+ rexmpp_xml_t *delete =
+ rexmpp_xml_new_elem("delete", "http://jabber.org/protocol/pubsub#owner");
+ rexmpp_xml_add_attr(delete, "node", node);
rexmpp_pubsub_iq(s, "set", "http://jabber.org/protocol/pubsub#owner",
service_jid, delete, callback, cb_data);
diff --git a/src/rexmpp_pubsub.h b/src/rexmpp_pubsub.h
index b5a7c3e..86675d3 100644
--- a/src/rexmpp_pubsub.h
+++ b/src/rexmpp_pubsub.h
@@ -11,7 +11,7 @@ rexmpp_pubsub_iq (rexmpp_t *s,
const char *iq_type,
const char *pubsub_namespace,
const char *service_jid,
- xmlNodePtr payload,
+ rexmpp_xml_t *payload,
rexmpp_iq_callback_t callback,
void *cb_data);
@@ -20,7 +20,7 @@ rexmpp_pubsub_item_publish (rexmpp_t *s,
const char *service_jid,
const char *node,
const char *item_id,
- xmlNodePtr payload,
+ rexmpp_xml_t *payload,
rexmpp_iq_callback_t callback,
void *cb_data);
diff --git a/src/rexmpp_roster.c b/src/rexmpp_roster.c
index 63a52b9..db09ff0 100644
--- a/src/rexmpp_roster.c
+++ b/src/rexmpp_roster.c
@@ -7,24 +7,25 @@
*/
#include "rexmpp.h"
+#include "rexmpp_xml.h"
#include <syslog.h>
#include <string.h>
#include <libxml/tree.h>
#include <libxml/xmlsave.h>
-xmlNodePtr rexmpp_roster_find_item (rexmpp_t *s,
- const char *jid,
- xmlNodePtr *prev_item)
+rexmpp_xml_t *
+rexmpp_roster_find_item (rexmpp_t *s,
+ const char *jid,
+ rexmpp_xml_t **prev_item)
{
- xmlNodePtr prev = NULL, cur = s->roster_items;
+ rexmpp_xml_t *prev = NULL, *cur = s->roster_items;
while (cur != NULL) {
- char *cur_jid = xmlGetProp(cur, "jid");
+ const char *cur_jid = rexmpp_xml_find_attr_val(cur, "jid");
if (cur_jid == NULL) {
rexmpp_log(s, LOG_ALERT, "No jid found in a roster item.");
return NULL;
}
int match = (strcmp(cur_jid, jid) == 0);
- free(cur_jid);
if (match) {
if (prev_item != NULL) {
*prev_item = prev;
@@ -37,17 +38,17 @@ xmlNodePtr rexmpp_roster_find_item (rexmpp_t *s,
return NULL;
}
-rexmpp_err_t rexmpp_modify_roster (rexmpp_t *s, xmlNodePtr item) {
+rexmpp_err_t rexmpp_modify_roster (rexmpp_t *s, rexmpp_xml_t *item) {
rexmpp_err_t ret = REXMPP_SUCCESS;
if (! rexmpp_xml_match(item, "jabber:iq:roster", "item")) {
rexmpp_log(s, LOG_ERR, "No roster item.");
return REXMPP_E_PARAM;
}
- char *subscription = xmlGetProp(item, "subscription");
- char *jid = xmlGetProp(item, "jid");
+ const char *subscription = rexmpp_xml_find_attr_val(item, "subscription");
+ const char *jid = rexmpp_xml_find_attr_val(item, "jid");
if (subscription != NULL && strcmp(subscription, "remove") == 0) {
/* Delete the item. */
- xmlNodePtr prev, cur;
+ rexmpp_xml_t *prev, *cur;
cur = rexmpp_roster_find_item(s, jid, &prev);
if (cur != NULL) {
if (prev != NULL) {
@@ -55,13 +56,13 @@ rexmpp_err_t rexmpp_modify_roster (rexmpp_t *s, xmlNodePtr item) {
} else {
s->roster_items = cur->next;
}
- xmlFreeNode(cur);
+ rexmpp_xml_free(cur);
} else {
ret = REXMPP_E_ROSTER_ITEM_NOT_FOUND;
}
} else {
/* Add or modify the item. */
- xmlNodePtr cur, prev;
+ rexmpp_xml_t *cur, *prev;
cur = rexmpp_roster_find_item(s, jid, &prev);
/* Remove the item if it was in the roster before. */
if (cur != NULL) {
@@ -70,37 +71,33 @@ rexmpp_err_t rexmpp_modify_roster (rexmpp_t *s, xmlNodePtr item) {
} else {
s->roster_items = cur->next;
}
- xmlFreeNode(cur);
+ rexmpp_xml_free(cur);
}
/* Add the new item. */
- xmlNodePtr new_item = xmlCopyNode(item, 1);
+ rexmpp_xml_t *new_item = rexmpp_xml_clone(item);
new_item->next = s->roster_items;
s->roster_items = new_item;
}
- free(jid);
- if (subscription != NULL) {
- free(subscription);
- }
if (s->roster_modify_cb != NULL) {
s->roster_modify_cb(s, item);
}
return ret;
}
-void rexmpp_roster_set (rexmpp_t *s, xmlNodePtr query) {
+void rexmpp_roster_set (rexmpp_t *s, rexmpp_xml_t *query) {
if (s->roster_items != NULL) {
- xmlFreeNodeList(s->roster_items);
+ rexmpp_xml_free_list(s->roster_items);
}
if (s->roster_ver != NULL) {
free(s->roster_ver);
}
- s->roster_ver = xmlGetProp(query, "ver");
- s->roster_items = xmlCopyNodeList(xmlFirstElementChild(query));
+ s->roster_ver = strdup(rexmpp_xml_find_attr_val(query, "ver"));
+ s->roster_items = rexmpp_xml_clone_list(query->alt.elem.children);
if (s->roster_modify_cb != NULL) {
- xmlNodePtr item;
- for (item = xmlFirstElementChild(query);
+ rexmpp_xml_t *item;
+ for (item = query->alt.elem.children;
item != NULL;
- item = xmlNextElementSibling(item))
+ item = item->next)
{
s->roster_modify_cb(s, item);
}
@@ -112,10 +109,11 @@ void rexmpp_roster_cache_read (rexmpp_t *s) {
rexmpp_log(s, LOG_WARNING, "No roster cache file path is set.");
return;
}
- xmlDocPtr doc = xmlReadFile(s->roster_cache_file, "utf-8", XML_PARSE_NONET);
- xmlNodePtr query = xmlDocGetRootElement(doc);
- rexmpp_roster_set(s, query);
- xmlFreeDoc(doc);
+ rexmpp_xml_t *query = rexmpp_xml_read_file(s->roster_cache_file);
+ if (query != NULL) {
+ rexmpp_roster_set(s, query);
+ rexmpp_xml_free(query);
+ }
}
void rexmpp_roster_cache_write (rexmpp_t *s) {
@@ -123,24 +121,22 @@ void rexmpp_roster_cache_write (rexmpp_t *s) {
rexmpp_log(s, LOG_WARNING, "No roster cache file path is set.");
return;
}
- xmlDocPtr doc = xmlNewDoc("1.0");
- xmlNodePtr query = xmlNewDocNode(doc, NULL, "query", NULL);
- xmlDocSetRootElement(doc, query);
- xmlNewNs(query, "jabber:iq:roster", NULL);
+
+ rexmpp_xml_t *query = rexmpp_xml_new_elem("query", "jabber:iq:roster");
if (s->roster_ver != NULL) {
- xmlNewProp(query, "ver", s->roster_ver);
+ rexmpp_xml_add_attr(query, "ver", s->roster_ver);
}
if (s->roster_items != NULL) {
- xmlAddChild(query, xmlDocCopyNodeList(doc, s->roster_items));
+ rexmpp_xml_add_child(query, rexmpp_xml_clone_list(s->roster_items));
}
- xmlSaveFileEnc(s->roster_cache_file, doc, "utf-8");
- xmlFreeDoc(doc);
+ rexmpp_xml_write_file(s->roster_cache_file, query);
+ rexmpp_xml_free(query);
}
void rexmpp_iq_roster_get (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success)
{
(void)ptr;
@@ -149,7 +145,7 @@ void rexmpp_iq_roster_get (rexmpp_t *s,
rexmpp_log(s, LOG_ERR, "Roster loading failed.");
return;
}
- xmlNodePtr query = xmlFirstElementChild(response);
+ rexmpp_xml_t *query = response->alt.elem.children;
if (! rexmpp_xml_match(query, "jabber:iq:roster", "query")) {
rexmpp_log(s, LOG_DEBUG, "No roster query in reply.");
return;
diff --git a/src/rexmpp_roster.h b/src/rexmpp_roster.h
index 1fa9183..f613a7b 100644
--- a/src/rexmpp_roster.h
+++ b/src/rexmpp_roster.h
@@ -7,15 +7,15 @@
*/
-xmlNodePtr rexmpp_roster_find_item (rexmpp_t *s,
- const char *jid,
- xmlNodePtr *prev_item);
-rexmpp_err_t rexmpp_modify_roster (rexmpp_t *s, xmlNodePtr item);
-void rexmpp_roster_set (rexmpp_t *s, xmlNodePtr query);
+rexmpp_xml_t *rexmpp_roster_find_item (rexmpp_t *s,
+ const char *jid,
+ rexmpp_xml_t **prev_item);
+rexmpp_err_t rexmpp_modify_roster (rexmpp_t *s, rexmpp_xml_t *item);
+void rexmpp_roster_set (rexmpp_t *s, rexmpp_xml_t *query);
void rexmpp_roster_cache_read (rexmpp_t *s);
void rexmpp_roster_cache_write (rexmpp_t *s);
void rexmpp_iq_roster_get (rexmpp_t *s,
void *ptr,
- xmlNodePtr req,
- xmlNodePtr response,
+ rexmpp_xml_t *req,
+ rexmpp_xml_t *response,
int success);
diff --git a/src/rexmpp_xml.c b/src/rexmpp_xml.c
new file mode 100644
index 0000000..8c91d32
--- /dev/null
+++ b/src/rexmpp_xml.c
@@ -0,0 +1,592 @@
+/**
+ @file rexmpp_xml.c
+ @brief XML structures and functions for rexmpp
+ @author defanor <defanor@uberspace.net>
+ @date 2023
+ @copyright MIT license.
+*/
+
+#include <string.h>
+#include <libxml/tree.h>
+#include <libxml/xmlsave.h>
+#include "rexmpp.h"
+#include "rexmpp_xml.h"
+
+void rexmpp_xml_qname_free (rexmpp_xml_qname_t *qname) {
+ if (qname->name != NULL) {
+ free(qname->name);
+ qname->name = NULL;
+ }
+ if (qname->namespace != NULL) {
+ free(qname->namespace);
+ qname->namespace = NULL;
+ }
+}
+
+void rexmpp_xml_attribute_free (rexmpp_xml_attr_t *attr) {
+ if (attr == NULL) {
+ return;
+ }
+ rexmpp_xml_qname_free(&(attr->qname));
+ if (attr->value != NULL) {
+ free(attr->value);
+ attr->value = NULL;
+ }
+ free(attr);
+}
+
+void rexmpp_xml_attribute_free_list (rexmpp_xml_attr_t *attr) {
+ rexmpp_xml_attr_t *next = attr;
+ while (attr != NULL) {
+ next = attr->next;
+ rexmpp_xml_attribute_free(attr);
+ attr = next;
+ }
+}
+
+void rexmpp_xml_free (rexmpp_xml_t *node) {
+ if (node == NULL) {
+ return;
+ }
+ if (node->type == REXMPP_XML_TEXT) {
+ if (node->alt.text != NULL) {
+ free(node->alt.text);
+ node->alt.text = NULL;
+ }
+ } if (node->type == REXMPP_XML_ELEMENT) {
+ rexmpp_xml_qname_free(&(node->alt.elem.qname));
+ rexmpp_xml_attribute_free_list(node->alt.elem.attributes);
+ rexmpp_xml_free_list(node->alt.elem.children);
+ }
+ free(node);
+}
+
+void rexmpp_xml_free_list (rexmpp_xml_t *node) {
+ rexmpp_xml_t *next = node;
+ while (node != NULL) {
+ next = node->next;
+ rexmpp_xml_free(node);
+ node = next;
+ }
+}
+
+rexmpp_xml_t *rexmpp_xml_clone (rexmpp_xml_t *node) {
+ if (node == NULL) {
+ return NULL;
+ }
+
+ if (node->type == REXMPP_XML_TEXT) {
+ return rexmpp_xml_new_text(node->alt.text);
+ } else if (node->type == REXMPP_XML_ELEMENT) {
+ rexmpp_xml_t *ret =
+ rexmpp_xml_new_elem(node->alt.elem.qname.name,
+ node->alt.elem.qname.namespace);
+ rexmpp_xml_attr_t **next_attr = &(ret->alt.elem.attributes);
+ rexmpp_xml_attr_t *old_attr;
+ for (old_attr = node->alt.elem.attributes;
+ old_attr != NULL;
+ old_attr = old_attr->next)
+ {
+ rexmpp_xml_attr_t *new_attr =
+ rexmpp_xml_attr_new(old_attr->qname.name,
+ old_attr->qname.namespace,
+ old_attr->value);
+ *next_attr = new_attr;
+ next_attr = &(new_attr->next);
+ }
+
+ ret->alt.elem.children =
+ rexmpp_xml_clone_list(node->alt.elem.children);
+ return ret;
+ }
+ return NULL;
+}
+
+rexmpp_xml_t *rexmpp_xml_clone_list (rexmpp_xml_t *node) {
+ rexmpp_xml_t *first, *last;
+ if (node == NULL) {
+ return NULL;
+ }
+ first = rexmpp_xml_clone(node);
+ for (last = first, node = node->next;
+ node != NULL;
+ last = last->next, node = node->next)
+ {
+ last->next = rexmpp_xml_clone(node);
+ }
+ return first;
+}
+
+
+rexmpp_xml_t *rexmpp_xml_from_libxml2 (xmlNodePtr from) {
+ if (from == NULL) {
+ return NULL;
+ }
+
+ rexmpp_xml_t *to = NULL;
+ if (from->type == XML_ELEMENT_NODE) {
+ to = malloc(sizeof(rexmpp_xml_t));
+
+ /* Type */
+ to->type = REXMPP_XML_ELEMENT;
+
+ /* Name and namespace */
+ to->alt.elem.qname.name = strdup(from->name);
+ if (from->nsDef != NULL && from->nsDef->href != NULL) {
+ to->alt.elem.qname.namespace = strdup(from->nsDef->href);
+ } else {
+ to->alt.elem.qname.namespace = NULL;
+ }
+
+ /* Attributes */
+ to->alt.elem.attributes = NULL;
+ struct _xmlAttr *from_attr;
+ rexmpp_xml_attr_t **to_next_attr = &(to->alt.elem.attributes);
+ for (from_attr = from->properties;
+ from_attr != NULL;
+ from_attr = from_attr->next)
+ {
+ rexmpp_xml_attr_t *to_attr =
+ malloc(sizeof(rexmpp_xml_attr_t));
+ to_attr->qname.name = strdup(from_attr->name);
+ to_attr->qname.namespace = NULL;
+ if (from_attr->ns != NULL && from_attr->ns->href != NULL) {
+ to_attr->qname.namespace = strdup(from_attr->ns->href);
+ to_attr->value =
+ xmlGetNsProp(from, to_attr->qname.name, to_attr->qname.namespace);
+ } else {
+ to_attr->value = xmlGetProp(from, to_attr->qname.name);
+ }
+ to_attr->next = NULL;
+
+ *to_next_attr = to_attr;
+ to_next_attr = &(to_attr->next);
+ }
+
+ /* Children */
+ to->alt.elem.children = NULL;
+ xmlNodePtr from_child;
+ rexmpp_xml_t **to_next_child = &(to->alt.elem.children);
+ for (from_child = from->children;
+ from_child != NULL;
+ from_child = from_child->next)
+ {
+ rexmpp_xml_t *next_child = rexmpp_xml_from_libxml2(from_child);
+ if (next_child != NULL) {
+ *to_next_child = next_child;
+ to_next_child = &(next_child->next);
+ }
+ }
+
+ /* Next */
+ to->next = NULL;
+
+ } else if (from->type == XML_TEXT_NODE) {
+ to = malloc(sizeof(rexmpp_xml_t));
+ to->type = REXMPP_XML_TEXT;
+ to->alt.text = xmlNodeGetContent(from);
+ to->next = NULL;
+ }
+ return to;
+}
+
+rexmpp_xml_t *rexmpp_xml_from_libxml2_list (xmlNodePtr from) {
+ if (from == NULL) {
+ return NULL;
+ }
+ rexmpp_xml_t *to = rexmpp_xml_from_libxml2(from);
+ if (from->next != NULL) {
+ to->next = rexmpp_xml_from_libxml2_list(from->next);
+ }
+ return to;
+}
+
+xmlNodePtr rexmpp_xml_to_libxml2 (rexmpp_xml_t *from) {
+ if (from == NULL) {
+ return NULL;
+ }
+
+ if (from->type == REXMPP_XML_TEXT) {
+ xmlNodePtr to = xmlNewText(from->alt.text);
+ to->next = rexmpp_xml_to_libxml2(from->next);
+ return to;
+ }
+
+ /* Name and namespace */
+ xmlNodePtr to = xmlNewNode(NULL, from->alt.elem.qname.name);
+ if (from->alt.elem.qname.namespace != NULL) {
+ xmlNewNs(to, from->alt.elem.qname.namespace, NULL);
+ }
+
+ /* Attributes */
+ rexmpp_xml_attr_t *attr = from->alt.elem.attributes;
+ while (attr != NULL) {
+ /* TODO: Would be nice to take namespaces into account, though
+ they are currently not used for attributes. */
+ xmlNewProp(to, attr->qname.name, attr->value);
+ attr = attr->next;
+ }
+
+ /* Children */
+ rexmpp_xml_t *child = from->alt.elem.children;
+ while (child != NULL) {
+ xmlAddChild(to, rexmpp_xml_to_libxml2(child));
+ child = child->next;
+ }
+ return to;
+}
+
+xmlNodePtr rexmpp_xml_to_libxml2_list (rexmpp_xml_t *from) {
+ xmlNodePtr to = rexmpp_xml_to_libxml2(from);
+ if (from->next != NULL) {
+ xmlAddNextSibling(to, rexmpp_xml_to_libxml2_list(from->next));
+ }
+ return to;
+}
+
+rexmpp_xml_t *rexmpp_xml_new_text (const char *str) {
+ rexmpp_xml_t *node = malloc(sizeof(rexmpp_xml_t));
+ node->type = REXMPP_XML_TEXT;
+ node->alt.text = strdup(str);
+ node->next = NULL;
+ return node;
+}
+
+void rexmpp_xml_add_child (rexmpp_xml_t *node,
+ rexmpp_xml_t *child)
+{
+ rexmpp_xml_t **last_ptr = &(node->alt.elem.children);
+ while (*last_ptr != NULL) {
+ last_ptr = &((*last_ptr)->next);
+ }
+ *last_ptr = child;
+}
+
+int rexmpp_xml_add_text (rexmpp_xml_t *node,
+ const char *str)
+{
+ rexmpp_xml_t *text_node = rexmpp_xml_new_text(str);
+ if (text_node != NULL) {
+ rexmpp_xml_add_child(node, text_node);
+ return 0;
+ }
+ return -1;
+}
+
+
+rexmpp_xml_t *rexmpp_xml_new_elem (const char *name,
+ const char *namespace)
+{
+ rexmpp_xml_t *node = malloc(sizeof(rexmpp_xml_t));
+ node->type = REXMPP_XML_ELEMENT;
+ node->alt.elem.qname.name = strdup(name);
+ if (namespace != NULL) {
+ node->alt.elem.qname.namespace = strdup(namespace);
+ } else {
+ node->alt.elem.qname.namespace = NULL;
+ }
+ node->alt.elem.attributes = NULL;
+ node->alt.elem.children = NULL;
+ node->next = NULL;
+ return node;
+}
+
+rexmpp_xml_attr_t *rexmpp_xml_attr_new (const char *name,
+ const char *namespace,
+ const char *value)
+{
+ rexmpp_xml_attr_t *attr = malloc(sizeof(rexmpp_xml_attr_t));
+ attr->qname.name = strdup(name);
+ if (namespace != NULL) {
+ attr->qname.namespace = strdup(namespace);
+ } else {
+ attr->qname.namespace = NULL;
+ }
+ attr->value = strdup(value);
+ attr->next = NULL;
+ return attr;
+}
+
+int rexmpp_xml_add_attr_ns (rexmpp_xml_t *node,
+ const char *name,
+ const char *namespace,
+ const char *value)
+{
+ if (node == NULL || node->type != REXMPP_XML_ELEMENT) {
+ return -1;
+ }
+ rexmpp_xml_attr_t *attr =
+ rexmpp_xml_attr_new(name, namespace, value);
+ attr->next = node->alt.elem.attributes;
+ node->alt.elem.attributes = attr;
+ return 0;
+}
+
+int rexmpp_xml_remove_attr_ns (rexmpp_xml_t *node,
+ const char *name,
+ const char *namespace) {
+ if (node == NULL || node->type != REXMPP_XML_ELEMENT) {
+ return -1;
+ }
+
+ rexmpp_xml_attr_t **attr, *next_attr;
+ for (attr = &(node->alt.elem.attributes); *attr != NULL; attr = &((*attr)->next)) {
+ if (rexmpp_xml_attr_match(*attr, namespace, name)) {
+ next_attr = (*attr)->next;
+ rexmpp_xml_attribute_free(*attr);
+ *attr = next_attr;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int rexmpp_xml_add_attr (rexmpp_xml_t *node,
+ const char *name,
+ const char *value)
+{
+ return rexmpp_xml_add_attr_ns(node, name, NULL, value);
+}
+
+int rexmpp_xml_remove_attr (rexmpp_xml_t *node,
+ const char *name) {
+ return rexmpp_xml_remove_attr_ns(node, name, NULL);
+}
+
+rexmpp_xml_t *
+rexmpp_xml_add_id (rexmpp_t *s,
+ rexmpp_xml_t *node)
+{
+ char *buf = rexmpp_gen_id(s);
+ if (buf == NULL) {
+ return NULL;
+ }
+ rexmpp_xml_add_attr(node, "id", buf);
+ free(buf);
+ return node;
+}
+
+char *rexmpp_xml_serialize (rexmpp_xml_t *node) {
+ xmlNodePtr node_libxml2 = rexmpp_xml_to_libxml2(node);
+ xmlBufferPtr buf = xmlBufferCreate();
+ xmlSaveCtxtPtr ctx = xmlSaveToBuffer(buf, "utf-8", 0);
+ xmlSaveTree(ctx, node_libxml2);
+ xmlSaveFlush(ctx);
+ xmlSaveClose(ctx);
+ unsigned char *out = xmlBufferDetach(buf);
+ xmlBufferFree(buf);
+ xmlFreeNode(node_libxml2);
+ return out;
+}
+
+xmlNodePtr rexmpp_xml_parse_libxml2 (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;
+}
+
+rexmpp_xml_t *rexmpp_xml_parse (const char *str, int str_len) {
+ xmlNodePtr node_lxml2 = rexmpp_xml_parse_libxml2(str, str_len);
+ if (node_lxml2 != NULL) {
+ rexmpp_xml_t *node = rexmpp_xml_from_libxml2(node_lxml2);
+ xmlFreeNode(node_lxml2);
+ return node;
+ }
+ return NULL;
+}
+
+rexmpp_xml_t *rexmpp_xml_read_file (const char *path) {
+ xmlDocPtr doc = xmlReadFile(path, "utf-8", XML_PARSE_NONET);
+ xmlNodePtr lxml2 = xmlDocGetRootElement(doc);
+ rexmpp_xml_t *ret = rexmpp_xml_from_libxml2(lxml2);
+ xmlFreeDoc(doc);
+ return ret;
+}
+
+int rexmpp_xml_write_file (const char *path, rexmpp_xml_t* node) {
+ xmlDocPtr doc = xmlNewDoc("1.0");
+ xmlNodePtr node_lxml2 = rexmpp_xml_to_libxml2(node);
+ xmlDocSetRootElement(doc, node_lxml2);
+ xmlSaveFileEnc(path, doc, "utf-8");
+ xmlFreeDoc(doc);
+ return 0;
+}
+
+unsigned int rexmpp_xml_siblings_count (rexmpp_xml_t *node) {
+ unsigned int i = 0;
+ for (i = 0; node != NULL; i++) {
+ node = node->next;
+ }
+ return i;
+}
+
+int rexmpp_xml_match (rexmpp_xml_t *node,
+ const char *namespace,
+ const char *name)
+{
+ if (node == NULL) {
+ return 0;
+ }
+ if (node->type != REXMPP_XML_ELEMENT) {
+ return 0;
+ }
+ if (name != NULL) {
+ if (strcmp(name, node->alt.elem.qname.name) != 0) {
+ return 0;
+ }
+ }
+ if (namespace != NULL) {
+ if (node->alt.elem.qname.namespace == NULL &&
+ strcmp(namespace, "jabber:client") != 0) {
+ return 0;
+ } else if (node->alt.elem.qname.namespace != NULL) {
+ if (strcmp(namespace, node->alt.elem.qname.namespace) != 0) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+int rexmpp_xml_attr_match (rexmpp_xml_attr_t *attr,
+ const char *namespace,
+ const char *name)
+{
+ if (attr == NULL) {
+ return 0;
+ }
+ if (name != NULL) {
+ if (strcmp(name, attr->qname.name) != 0) {
+ return 0;
+ }
+ }
+ if (namespace != NULL) {
+ if (attr->qname.namespace == NULL &&
+ strcmp(namespace, "jabber:client") != 0) {
+ return 0;
+ } else if (strcmp(namespace, attr->qname.namespace) != 0) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int rexmpp_xml_is_stanza (rexmpp_xml_t *node) {
+ return rexmpp_xml_match(node, "jabber:client", "message") ||
+ rexmpp_xml_match(node, "jabber:client", "iq") ||
+ rexmpp_xml_match(node, "jabber:client", "presence");
+}
+
+rexmpp_xml_t *rexmpp_xml_error (const char *type, const char *condition) {
+ rexmpp_xml_t * error = rexmpp_xml_new_elem("error", NULL);
+ rexmpp_xml_add_attr(error, "type", type);
+ rexmpp_xml_t * cond =
+ rexmpp_xml_new_elem(condition, "urn:ietf:params:xml:ns:xmpp-stanzas");
+ rexmpp_xml_add_child(error, cond);
+ return error;
+}
+
+rexmpp_xml_attr_t *
+rexmpp_xml_find_attr (rexmpp_xml_t *node,
+ const char *name,
+ const char *namespace)
+{
+ if (node == NULL || node->type != REXMPP_XML_ELEMENT) {
+ return NULL;
+ }
+ rexmpp_xml_attr_t *attr;
+ for (attr = node->alt.elem.attributes; attr != NULL; attr = attr->next) {
+ if (rexmpp_xml_attr_match(attr, namespace, name)) {
+ return attr;
+ }
+ }
+ return NULL;
+}
+
+const char *rexmpp_xml_find_attr_val_ns (rexmpp_xml_t *node,
+ const char *name,
+ const char *namespace) {
+ rexmpp_xml_attr_t *attr = rexmpp_xml_find_attr(node, name, namespace);
+ if (attr != NULL) {
+ return attr->value;
+ }
+ return NULL;
+}
+
+const char *rexmpp_xml_find_attr_val (rexmpp_xml_t *node,
+ const char *name) {
+ return rexmpp_xml_find_attr_val_ns(node, name, NULL);
+}
+
+rexmpp_xml_t *
+rexmpp_xml_find_child (rexmpp_xml_t *node,
+ const char *namespace,
+ const char *name)
+{
+ if (node == NULL || node->type != REXMPP_XML_ELEMENT) {
+ return NULL;
+ }
+ rexmpp_xml_t *child;
+ for (child = node->alt.elem.children; child != NULL; child = child->next) {
+ if (rexmpp_xml_match(child, namespace, name)) {
+ return child;
+ }
+ }
+ return NULL;
+}
+
+int rexmpp_xml_eq (rexmpp_xml_t *n1, rexmpp_xml_t *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;
+}
+
+rexmpp_xml_t *rexmpp_xml_children (rexmpp_xml_t *node) {
+ if (node != NULL && node->type == REXMPP_XML_ELEMENT) {
+ return node->alt.elem.children;
+ }
+ return NULL;
+}
+
+rexmpp_xml_t *rexmpp_xml_first_elem_child (rexmpp_xml_t *node) {
+ rexmpp_xml_t *child;
+ for (child = rexmpp_xml_children(node); child != NULL; child = child->next) {
+ if (child->type == REXMPP_XML_ELEMENT) {
+ return child;
+ }
+ }
+ return NULL;
+}
+
+rexmpp_xml_t *rexmpp_xml_next_elem_sibling (rexmpp_xml_t *node) {
+ if (node == NULL) {
+ return NULL;
+ }
+ rexmpp_xml_t *sibling;
+ for (sibling = node->next; sibling != NULL; sibling = sibling->next) {
+ if (sibling->type == REXMPP_XML_ELEMENT) {
+ return sibling;
+ }
+ }
+ return NULL;
+}
+
+const char *rexmpp_xml_text (rexmpp_xml_t *node) {
+ if (node != NULL && node->type == REXMPP_XML_TEXT) {
+ return node->alt.text;
+ }
+ return NULL;
+}
+
+const char *rexmpp_xml_text_child (rexmpp_xml_t *node) {
+ return rexmpp_xml_text(rexmpp_xml_children(node));
+}
diff --git a/src/rexmpp_xml.h b/src/rexmpp_xml.h
new file mode 100644
index 0000000..33f61f2
--- /dev/null
+++ b/src/rexmpp_xml.h
@@ -0,0 +1,232 @@
+/**
+ @file rexmpp_xml.h
+ @brief XML structures and functions for rexmpp
+ @author defanor <defanor@uberspace.net>
+ @date 2023
+ @copyright MIT license.
+*/
+
+#ifndef REXMPP_XML_H
+#define REXMPP_XML_H
+
+#include <libxml/tree.h>
+
+typedef struct rexmpp_xml_qname rexmpp_xml_qname_t;
+typedef struct rexmpp_xml_attribute rexmpp_xml_attr_t;
+typedef struct rexmpp_xml_node rexmpp_xml_t;
+
+struct rexmpp_xml_qname {
+ char *name;
+ char *namespace;
+};
+
+struct rexmpp_xml_attribute {
+ rexmpp_xml_qname_t qname;
+ char *value;
+ rexmpp_xml_attr_t *next;
+};
+
+enum rexmpp_xml_node_type {
+ REXMPP_XML_ELEMENT,
+ REXMPP_XML_TEXT
+};
+
+typedef enum rexmpp_xml_node_type rexmpp_xml_node_type_t;
+
+struct rexmpp_xml_node {
+ rexmpp_xml_node_type_t type;
+ union {
+ struct {
+ rexmpp_xml_qname_t qname;
+ rexmpp_xml_attr_t *attributes;
+ rexmpp_xml_t *children;
+ } elem;
+ char *text;
+ } alt;
+ rexmpp_xml_t *next;
+};
+
+
+/**
+ @brief Frees a single XML node. Does not free its siblings.
+*/
+void rexmpp_xml_free (rexmpp_xml_t *node);
+
+/**
+ @brief Frees an XML node and its siblings.
+*/
+void rexmpp_xml_free_list (rexmpp_xml_t *node);
+
+/**
+ @brief Clones a single XML node, without its siblings.
+*/
+rexmpp_xml_t *rexmpp_xml_clone (rexmpp_xml_t *node);
+
+/**
+ @brief Clones an XML node, together with its siblings.
+*/
+rexmpp_xml_t *rexmpp_xml_clone_list (rexmpp_xml_t *node);
+
+/**
+ @brief Creates a single ::rexmpp_xml_t XML node out of libxml2's
+ xmlNode, without siblings.
+*/
+rexmpp_xml_t *rexmpp_xml_from_libxml2 (xmlNodePtr from);
+
+/**
+ @brief Creates a ::rexmpp_xml_t XML node out of libxml2's xmlNode,
+ with siblings.
+*/
+rexmpp_xml_t *rexmpp_xml_from_libxml2_list (xmlNodePtr from);
+
+xmlNodePtr rexmpp_xml_to_libxml2 (rexmpp_xml_t *from);
+
+xmlNodePtr rexmpp_xml_to_libxml2_list (rexmpp_xml_t *from);
+
+/**
+ @brief Creates a textual ::rexmpp_xml_t XML node (with type =
+ ::REXMPP_XML_TEXT).
+*/
+rexmpp_xml_t *rexmpp_xml_new_text (const char *str);
+
+/**
+ @brief Creates an element ::rexmpp_xml_t XML node (with type =
+ ::REXMPP_XML_ELEMENT).
+*/
+rexmpp_xml_t *rexmpp_xml_new_elem (const char *name,
+ const char *namespace);
+
+/**
+ @brief Adds a child node.
+*/
+void rexmpp_xml_add_child (rexmpp_xml_t *node,
+ rexmpp_xml_t *child);
+
+/**
+ @brief Creates a text node, and adds it as a child.
+*/
+int rexmpp_xml_add_text (rexmpp_xml_t *node,
+ const char *str);
+
+rexmpp_xml_attr_t *rexmpp_xml_attr_new (const char *name,
+ const char *namespace,
+ const char *value);
+
+int rexmpp_xml_add_attr (rexmpp_xml_t *node,
+ const char *name,
+ const char *value);
+
+int rexmpp_xml_remove_attr_ns (rexmpp_xml_t *node,
+ const char *name,
+ const char *namespace);
+
+int rexmpp_xml_remove_attr (rexmpp_xml_t *node,
+ const char *name);
+
+int rexmpp_xml_add_attr_ns (rexmpp_xml_t *node,
+ const char *name,
+ const char *namespace,
+ const char *value);
+
+/**
+ @brief Adds an "id" attribute to an XML stanza.
+ @param[in,out] s ::rexmpp
+ @param[in] node A pointer to an XML stanza.
+ @returns The same pointer as on input, for more convenient
+ composition.
+*/
+rexmpp_xml_t *
+rexmpp_xml_add_id (rexmpp_t *s,
+ rexmpp_xml_t *node);
+
+/**
+ @brief A helper function for XML serialisation.
+ @param[in] node An XML node.
+ @returns A string (must be freed by the caller).
+*/
+char *rexmpp_xml_serialize (rexmpp_xml_t *node);
+
+/**
+ @brief Count the number of siblings after a given node.
+*/
+unsigned int rexmpp_xml_siblings_count (rexmpp_xml_t *node);
+
+/**
+ @brief Compares the node's name and namespace to given ones.
+*/
+int rexmpp_xml_match (rexmpp_xml_t *node,
+ const char *namespace,
+ const char *name);
+
+int rexmpp_xml_is_stanza (rexmpp_xml_t *node);
+
+/**
+ @brief Compose an 'error' element.
+*/
+rexmpp_xml_t *rexmpp_xml_error (const char *type, const char *condition);
+
+/**
+ @brief Matches an XML node against a namespace and an element name.
+ @param[in] node An XML node to match.
+ @param[in] namespace An XML namespace. Can be NULL (matches
+ anything), and it is assumed that the default namespace is
+ "jabber:client" (so if it is "jabber:client" and an element doesn't
+ have a namespace defined, this function counts that as a match).
+ @param[in] name Element name. Can be NULL (matches anything).
+ @returns 1 on a successful match, 0 otherwise.
+*/
+int rexmpp_xml_attr_match (rexmpp_xml_attr_t *attr,
+ const char *namespace,
+ const char *name);
+
+rexmpp_xml_attr_t *rexmpp_xml_find_attr (rexmpp_xml_t *node,
+ const char *name,
+ const char *namespace);
+
+const char *rexmpp_xml_find_attr_val_ns (rexmpp_xml_t *node,
+ const char *name,
+ const char *namespace);
+
+const char *rexmpp_xml_find_attr_val (rexmpp_xml_t *node,
+ const char *name);
+
+/**
+ @brief Finds a child element of an XML node, which matches the
+ given namespace and name.
+ @param[in] node The node containing child nodes.
+ @param[in] namespace The namespace to look for.
+ @param[in] name The element name to look for.
+ @returns A pointer to the first matching child node, or NULL if no
+ matching child elements found.
+*/
+rexmpp_xml_t *rexmpp_xml_find_child (rexmpp_xml_t *node,
+ const char *namespace,
+ const char *name);
+
+rexmpp_xml_t *rexmpp_xml_children (rexmpp_xml_t *node);
+
+const char *rexmpp_xml_text (rexmpp_xml_t *node);
+
+const char *rexmpp_xml_text_child (rexmpp_xml_t *node);
+
+rexmpp_xml_t *rexmpp_xml_first_elem_child (rexmpp_xml_t *node);
+
+rexmpp_xml_t *rexmpp_xml_next_elem_sibling (rexmpp_xml_t *node);
+
+/**
+ @brief Compares two XML elements.
+*/
+int rexmpp_xml_eq (rexmpp_xml_t *n1, rexmpp_xml_t *n2);
+
+/**
+ @brief A helper function for XML parsing.
+ @param[in] str A string to parse.
+ @param[in] str_len String length.
+ @returns Parsed XML, or NULL on failure.
+*/
+rexmpp_xml_t *rexmpp_xml_parse (const char *str, int str_len);
+
+rexmpp_xml_t *rexmpp_xml_read_file (const char *path);
+int rexmpp_xml_write_file (const char *path, rexmpp_xml_t* node);
+
+#endif