diff --git a/.gitignore b/.gitignore index 08e1083..54c2f34 100644 --- a/.gitignore +++ b/.gitignore @@ -41,5 +41,6 @@ src/server/log.lo config.cache configure.lineno src/server/prime.lo +src/server/verify.lo stabbertest diff --git a/Makefile.am b/Makefile.am index f8b659d..587fe7f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,6 +7,7 @@ sources = \ src/server/stanza.c src/server/stanza.h \ src/server/log.c src/server/log.h \ src/server/prime.c src/server/prime.h \ + src/server/verify.c src/server/verify.h \ src/client/stabber.c src/client/stabber.h libstabber_la_LDFLAGS = -export-symbols-regex '^stbbr_' diff --git a/src/client/stabber.c b/src/client/stabber.c index 9872c06..da5992e 100644 --- a/src/client/stabber.c +++ b/src/client/stabber.c @@ -4,6 +4,7 @@ #include "server/server.h" #include "server/prime.h" +#include "server/verify.h" typedef struct server_args_t { int port; @@ -29,6 +30,12 @@ stbbr_for(char *id, char *stream) return 1; } +int +stbbr_verify_last(char *stanza) +{ + return verify_last(stanza); +} + void stbbr_stop(void) { diff --git a/src/server/server.h b/src/server/server.h index 6c463b2..9027042 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -3,4 +3,5 @@ int server_run(int port); void server_stop(void); + #endif diff --git a/src/server/stanza.c b/src/server/stanza.c index af409b9..2c6ddc8 100644 --- a/src/server/stanza.c +++ b/src/server/stanza.c @@ -164,6 +164,107 @@ stanza_get_id(XMPPStanza *stanza) return NULL; } +static int +_xmpp_attr_equal(XMPPAttr *attr1, XMPPAttr *attr2) +{ + if (g_strcmp0(attr1->name, attr2->name) != 0) { + return -1; + } + + if (g_strcmp0(attr1->value, attr2->value) != 0) { + return -1; + } + + return 0; +} + +static int +_stanzas_equal(XMPPStanza *first, XMPPStanza *second) +{ + // check name + if (g_strcmp0(first->name, second->name) != 0) { + return -1; + } + + // check attribute count + if (g_list_length(first->attrs) != g_list_length(second->attrs)) { + return -1; + } + + // check children count + if (g_list_length(first->children) != g_list_length(second->children)) { + return -1; + } + + // check presence of content + if (!first->content && second->content) { + return -1; + } + if (first->content && !second->content) { + return -1; + } + + // check content is exists + if (first->content) { + if (g_strcmp0(first->content->str, second->content->str) != 0) { + return -1; + } + } + + // check attributes + if (first->attrs) { + GList *first_curr_attr = first->attrs; + while (first_curr_attr) { + XMPPAttr *first_attr = (XMPPAttr *)first_curr_attr->data; + + GList *second_found_attr = g_list_find_custom(second->attrs, first_attr, (GCompareFunc)_xmpp_attr_equal); + if (!second_found_attr) { + return -1; + } + + first_curr_attr = g_list_next(first_curr_attr); + } + } + + // check children + if (first->children) { + GList *first_curr_child = first->children; + while (first_curr_child) { + XMPPStanza *first_child = (XMPPStanza *)first_curr_child->data; + GList *second_found_child = g_list_find_custom(second->children, first_child, (GCompareFunc)_stanzas_equal); + if (!second_found_child) { + return -1; + } + + first_curr_child = g_list_next(first_curr_child); + } + } + + return 0; +} + +int +stanza_verify_last(XMPPStanza *stanza) +{ + if (!stanzas) { + return 0; + } + + GList *last = g_list_last(stanzas); + if (!last) { + return 0; + } + + XMPPStanza *last_stanza = (XMPPStanza *)last->data; + + int res = _stanzas_equal(stanza, last_stanza); + if (res == 0) { + return 1; + } else { + return 0; + } +} + static void _attrs_free(XMPPAttr *attr) { @@ -174,8 +275,8 @@ _attrs_free(XMPPAttr *attr) } } -static void -_stanza_free(XMPPStanza *stanza) +void +stanza_free(XMPPStanza *stanza) { if (stanza) { free(stanza->name); @@ -183,7 +284,7 @@ _stanza_free(XMPPStanza *stanza) g_string_free(stanza->content, TRUE); } g_list_free_full(stanza->attrs, (GDestroyNotify)_attrs_free); - g_list_free_full(stanza->children, (GDestroyNotify)_stanza_free); + g_list_free_full(stanza->children, (GDestroyNotify)stanza_free); free(stanza); } } @@ -191,6 +292,6 @@ _stanza_free(XMPPStanza *stanza) void stanza_free_all(void) { - g_list_free_full(stanzas, (GDestroyNotify)_stanza_free); + g_list_free_full(stanzas, (GDestroyNotify)stanza_free); stanzas = NULL; } diff --git a/src/server/stanza.h b/src/server/stanza.h index 4e91f99..b9e652a 100644 --- a/src/server/stanza.h +++ b/src/server/stanza.h @@ -1,6 +1,8 @@ #ifndef __H_STANZA #define __H_STANZA +#include + typedef struct xmpp_attr_t { char *name; char *value; @@ -24,6 +26,9 @@ const char* stanza_get_id(XMPPStanza *stanza); XMPPStanza* stanza_get_child_by_ns(XMPPStanza *stanza, char *ns); XMPPStanza* stanza_get_child_by_name(XMPPStanza *stanza, char *name); +int stanza_verify_last(XMPPStanza *stanza); + +void stanza_free(XMPPStanza *stanza); void stanza_free_all(void); #endif diff --git a/src/server/verify.c b/src/server/verify.c new file mode 100644 index 0000000..966f79e --- /dev/null +++ b/src/server/verify.c @@ -0,0 +1,70 @@ +#include + +#include + +#include "server/stanza.h" +#include "server/log.h" + +static int depth = 0; +static XMPPStanza *curr_stanza = NULL; + +static void +start_element(void *data, const char *element, const char **attributes) +{ + XMPPStanza *stanza = stanza_new(element, attributes); + + if (depth == 0) { + curr_stanza = stanza; + curr_stanza->parent = NULL; + } else { + stanza->parent = curr_stanza; + curr_stanza = stanza; + } + + depth++; +} + +static void +end_element(void *data, const char *element) +{ + depth--; + + if (depth > 0) { + stanza_add_child(curr_stanza->parent, curr_stanza); + curr_stanza = curr_stanza->parent; + } +} + +static void +handle_data(void *data, const char *content, int length) +{ + if (!curr_stanza->content) { + curr_stanza->content = g_string_new(""); + } + + g_string_append_len(curr_stanza->content, content, length); +} + +int +verify_last(char *stanza_text) +{ + depth = 0; + if (curr_stanza) { + stanza_free(curr_stanza); + } + XML_Parser parser = XML_ParserCreate(NULL); + XML_SetElementHandler(parser, start_element, end_element); + XML_SetCharacterDataHandler(parser, handle_data); + + XML_Parse(parser, stanza_text, strlen(stanza_text), 0); + XML_ParserFree(parser); + + int result = stanza_verify_last(curr_stanza); + if (result) { + log_println("VERIFY SUCCESS: %s", stanza_text); + } else { + log_println("VERIFY FAIL: %s", stanza_text); + } + + return result; +} diff --git a/src/server/verify.h b/src/server/verify.h new file mode 100644 index 0000000..ee596d2 --- /dev/null +++ b/src/server/verify.h @@ -0,0 +1,6 @@ +#ifndef __H_VERIFY +#define __H_VERIFY + +int verify_last(char *stanza); + +#endif diff --git a/stabber.h b/stabber.h index aaf9ad1..2fb131b 100644 --- a/stabber.h +++ b/stabber.h @@ -7,4 +7,6 @@ void stbbr_stop(void); int stbbr_auth_passwd(char *password); void stbbr_for(char *id, char *stream); +int stbbr_verify_last(char *stanza); + #endif