mirror of
https://github.com/strophe/libstrophe.git
synced 2026-07-18 11:56:22 +00:00
Abstracted XML parser library and switched to autotools building.
expat is still the default parser, but libxml2 can also be used via an option to the configure script. New parsers can easily be added by implementing a parser_foo.c that uses the interface defined in parser.h.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,6 +14,7 @@ autom4te.cache
|
||||
src/*.o
|
||||
examples/*.o
|
||||
tests/*.o
|
||||
tests/check_parser
|
||||
*.a
|
||||
examples/basic
|
||||
examples/active
|
||||
|
||||
60
Makefile.am
Normal file
60
Makefile.am
Normal file
@@ -0,0 +1,60 @@
|
||||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
|
||||
CFLAGS = -g -Wall
|
||||
|
||||
builtin_CFLAGS = -I$(top_srcdir)/expat/lib
|
||||
builtin_LIBS = libexpat.a
|
||||
|
||||
PARSER_CFLAGS=@PARSER_CFLAGS@
|
||||
PARSER_LIBS=@PARSER_LIBS@
|
||||
|
||||
STROPHE_FLAGS = -I$(top_srcdir)
|
||||
STROPHE_LIBS = libstrophe.a $(PARSER_LIBS) -lssl -lresolv
|
||||
|
||||
## Main build targets
|
||||
if BUILD_EXPAT
|
||||
lib_LIBRARIES = libstrophe.a libexpat.a
|
||||
else
|
||||
lib_LIBRARIES = libstrophe.a
|
||||
endif
|
||||
|
||||
libstrophe_a_CFLAGS=$(STROPHE_FLAGS) $(PARSER_CFLAGS)
|
||||
libstrophe_a_SOURCES = src/auth.c src/conn.c src/ctx.c \
|
||||
src/event.c src/handler.c src/hash.c \
|
||||
src/jid.c src/md5.c src/sasl.c src/sha1.c \
|
||||
src/snprintf.c src/sock.c src/stanza.c src/thread.c \
|
||||
src/tls_openssl.c src/util.c
|
||||
if PARSER_EXPAT
|
||||
libstrophe_a_SOURCES += src/parser_expat.c
|
||||
else
|
||||
libstrophe_a_SOURCES += src/parser_libxml2.c
|
||||
endif
|
||||
|
||||
libexpat_a_CFLAGS=-DXML_DTD -DXML_NS -DXML_CONTEXT_BYTES=1024 -DXML_STATIC \
|
||||
-I$(top_srcdir)/expat/lib
|
||||
libexpat_a_SOURCES=expat/lib/xmlparse.c expat/lib/xmltok.c expat/lib/xmlrole.c
|
||||
|
||||
|
||||
## Examples
|
||||
noinst_PROGRAMS = examples/active examples/roster examples/basic examples/bot
|
||||
examples_active_SOURCES = examples/active.c
|
||||
examples_active_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_active_LDADD = $(STROPHE_LIBS)
|
||||
examples_roster_SOURCES = examples/roster.c
|
||||
examples_roster_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_roster_LDADD = $(STROPHE_LIBS)
|
||||
examples_basic_SOURCES = examples/basic.c
|
||||
examples_basic_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_basic_LDADD = $(STROPHE_LIBS)
|
||||
examples_bot_SOURCES = examples/bot.c
|
||||
examples_bot_CFLAGS = $(STROPHE_FLAGS)
|
||||
examples_bot_LDADD = $(STROPHE_LIBS)
|
||||
|
||||
|
||||
## Tests
|
||||
TESTS = tests/check_parser
|
||||
check_PROGRAMS = tests/check_parser
|
||||
tests_check_parser_SOURCES = tests/check_parser.c
|
||||
tests_check_parser_CFLAGS = @check_CFLAGS@ $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
|
||||
-I$(top_srcdir)/src
|
||||
tests_check_parser_LDADD = @check_LIBS@ $(STROPHE_LIBS)
|
||||
5
bootstrap.sh
Executable file
5
bootstrap.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
aclocal -I /usr/local/share/aclocal
|
||||
automake --add-missing --foreign --copy
|
||||
autoconf
|
||||
44
configure.ac
Normal file
44
configure.ac
Normal file
@@ -0,0 +1,44 @@
|
||||
AC_INIT([libstrophe], [trunk], [jack@metajack.im])
|
||||
AM_INIT_AUTOMAKE
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_RANLIB
|
||||
|
||||
PKG_CHECK_MODULES([check], [check >= 0.9.4])
|
||||
|
||||
AC_ARG_WITH([libxml2],
|
||||
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing])],
|
||||
[with_libxml2=check],
|
||||
[with_libxml2=no])
|
||||
|
||||
if test "x$with_libxml2" != xno; then
|
||||
PKG_CHECK_MODULES([libxml2], [libxml-2.0 >= 2.7],
|
||||
[with_libxml2=yes],
|
||||
[AC_MSG_ERROR([couldn't find libxml2])])
|
||||
else
|
||||
AC_CHECK_FUNCS(memmove)
|
||||
AC_C_BIGENDIAN([byteorder=1234], [byteorder=4321], [], [])
|
||||
fi
|
||||
|
||||
if test "x$with_libxml2" = xyes; then
|
||||
with_parser=libxml2
|
||||
PARSER_NAME=libxml2
|
||||
PARSER_CFLAGS=\$\(libxml2_CFLAGS\)
|
||||
PARSER_LIBS=\$\(libxml2_LIBS\)
|
||||
else
|
||||
with_parser=builtin
|
||||
PARSER_NAME=expat
|
||||
PARSER_CFLAGS=\$\(builtin_CFLAGS\)
|
||||
PARSER_LIBS=\$\(builtin_LIBS\)
|
||||
fi
|
||||
|
||||
AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser])
|
||||
|
||||
AM_CONDITIONAL([BUILD_EXPAT], [test x$with_parser = xbuiltin])
|
||||
AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2])
|
||||
AC_DEFINE_UNQUOTED([BYTEORDER], [$byteorder])
|
||||
AC_SUBST(PARSER_NAME)
|
||||
AC_SUBST(PARSER_CFLAGS)
|
||||
AC_SUBST(PARSER_LIBS)
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_OUTPUT
|
||||
23
src/auth.c
23
src/auth.c
@@ -208,9 +208,11 @@ static int _handle_features(xmpp_conn_t * const conn,
|
||||
xmpp_timed_handler_delete(conn, _handle_missing_features);
|
||||
|
||||
/* check for TLS */
|
||||
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
|
||||
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_TLS) == 0))
|
||||
conn->tls_support = 1;
|
||||
if (!conn->secured) {
|
||||
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
|
||||
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_TLS) == 0))
|
||||
conn->tls_support = 1;
|
||||
}
|
||||
|
||||
/* check for SASL */
|
||||
child = xmpp_stanza_get_child_by_name(stanza, "mechanisms");
|
||||
@@ -277,7 +279,8 @@ static int _handle_proceedtls_default(xmpp_conn_t * const conn,
|
||||
}
|
||||
else
|
||||
{
|
||||
parser_prepare_reset(conn, _handle_open_tls);
|
||||
conn->secured = 1;
|
||||
conn_prepare_reset(conn, auth_handle_open);
|
||||
|
||||
conn_open_stream(conn);
|
||||
}
|
||||
@@ -307,7 +310,7 @@ static int _handle_sasl_result(xmpp_conn_t * const conn,
|
||||
(char *)userdata);
|
||||
|
||||
/* reset parser */
|
||||
parser_prepare_reset(conn, _handle_open_sasl);
|
||||
conn_prepare_reset(conn, _handle_open_sasl);
|
||||
|
||||
/* send stream tag */
|
||||
conn_open_stream(conn);
|
||||
@@ -692,16 +695,6 @@ void auth_handle_open(xmpp_conn_t * const conn)
|
||||
FEATURES_TIMEOUT, NULL);
|
||||
}
|
||||
|
||||
/* called when stream:stream tag received after TLS connection */
|
||||
static void _handle_open_tls(xmpp_conn_t * const conn)
|
||||
{
|
||||
xmpp_debug(conn->ctx, "xmpp", "TLS successful, proceeding with SASL");
|
||||
|
||||
/* go straight to SASL auth */
|
||||
_auth(conn);
|
||||
}
|
||||
|
||||
|
||||
/* called when stream:stream tag received after SASL auth */
|
||||
static void _handle_open_sasl(xmpp_conn_t * const conn)
|
||||
{
|
||||
|
||||
23
src/common.h
23
src/common.h
@@ -31,8 +31,7 @@
|
||||
#include "tls.h"
|
||||
#include "hash.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "expat.h"
|
||||
#include "parser.h"
|
||||
|
||||
/** run-time context **/
|
||||
|
||||
@@ -167,6 +166,7 @@ struct _xmpp_conn_t {
|
||||
int tls_failed; /* set when tls fails, so we don't try again */
|
||||
int sasl_support; /* if true, field is a bitfield of supported
|
||||
mechanisms */
|
||||
int secured; /* set when stream is secured with TLS */
|
||||
|
||||
/* if server returns <bind/> or <session/> we must do them */
|
||||
int bind_required;
|
||||
@@ -189,9 +189,7 @@ struct _xmpp_conn_t {
|
||||
|
||||
/* xml parser */
|
||||
int reset_parser;
|
||||
XML_Parser parser;
|
||||
int depth;
|
||||
xmpp_stanza_t *stanza;
|
||||
parser_t *parser;
|
||||
|
||||
/* timeouts */
|
||||
unsigned int connect_timeout;
|
||||
@@ -217,6 +215,8 @@ struct _xmpp_conn_t {
|
||||
void conn_disconnect(xmpp_conn_t * const conn);
|
||||
void conn_disconnect_clean(xmpp_conn_t * const conn);
|
||||
void conn_open_stream(xmpp_conn_t * const conn);
|
||||
void conn_prepare_reset(xmpp_conn_t * const conn, xmpp_open_handler handler);
|
||||
void conn_parser_reset(xmpp_conn_t * const conn);
|
||||
|
||||
|
||||
typedef enum {
|
||||
@@ -241,19 +241,6 @@ struct _xmpp_stanza_t {
|
||||
hash_t *attributes;
|
||||
};
|
||||
|
||||
int xmpp_stanza_set_attributes(xmpp_stanza_t * const stanza,
|
||||
const char * const * const attr);
|
||||
|
||||
/* parser functions */
|
||||
void parser_handle_start(void *userdata,
|
||||
const XML_Char *name,
|
||||
const XML_Char **attr);
|
||||
void parser_handle_character(void *userdata, const XML_Char *s, int len);
|
||||
void parser_handle_end(void *userdata, const XML_Char *name);
|
||||
void parser_prepare_reset(xmpp_conn_t * const conn,
|
||||
xmpp_open_handler handler);
|
||||
int parser_reset(xmpp_conn_t * const conn);
|
||||
|
||||
/* handler management */
|
||||
void handler_fire_stanza(xmpp_conn_t * const conn,
|
||||
xmpp_stanza_t * const stanza);
|
||||
|
||||
137
src/conn.c
137
src/conn.c
@@ -23,9 +23,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "strophe.h"
|
||||
#include <strophe.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
#include "parser.h"
|
||||
|
||||
#ifndef DEFAULT_SEND_QUEUE_MAX
|
||||
/** @def DEFAULT_SEND_QUEUE_MAX
|
||||
@@ -51,6 +53,13 @@
|
||||
static int _disconnect_cleanup(xmpp_conn_t * const conn,
|
||||
void * const userdata);
|
||||
|
||||
static void _handle_stream_start(char *name, char **attrs,
|
||||
void * const userdata);
|
||||
static void _handle_stream_end(char *name,
|
||||
void * const userdata);
|
||||
static void _handle_stream_stanza(xmpp_stanza_t *stanza,
|
||||
void * const userdata);
|
||||
|
||||
/** Create a new Strophe connection object.
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
@@ -100,13 +109,18 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
|
||||
conn->tls_support = 0;
|
||||
conn->tls_failed = 0;
|
||||
conn->sasl_support = 0;
|
||||
conn->secured = 0;
|
||||
|
||||
conn->bind_required = 0;
|
||||
conn->session_required = 0;
|
||||
|
||||
conn->parser = NULL;
|
||||
conn->stanza = NULL;
|
||||
parser_prepare_reset(conn, auth_handle_open);
|
||||
conn->parser = parser_new(conn->ctx,
|
||||
_handle_stream_start,
|
||||
_handle_stream_end,
|
||||
_handle_stream_stanza,
|
||||
conn);
|
||||
conn->reset_parser = 0;
|
||||
conn_prepare_reset(conn, auth_handle_open);
|
||||
|
||||
conn->authenticated = 0;
|
||||
conn->conn_handler = NULL;
|
||||
@@ -127,7 +141,7 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
|
||||
if (!item) {
|
||||
xmpp_error(conn->ctx, "xmpp", "failed to allocate memory");
|
||||
xmpp_free(conn->ctx, conn->lang);
|
||||
XML_ParserFree(conn->parser);
|
||||
parser_free(conn->parser);
|
||||
xmpp_free(conn->ctx, conn);
|
||||
conn = NULL;
|
||||
} else {
|
||||
@@ -249,7 +263,7 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
|
||||
xmpp_free(ctx, conn->stream_error);
|
||||
}
|
||||
|
||||
XML_ParserFree(conn->parser);
|
||||
parser_free(conn->parser);
|
||||
|
||||
if (conn->domain) xmpp_free(ctx, conn->domain);
|
||||
if (conn->jid) xmpp_free(ctx, conn->jid);
|
||||
@@ -361,7 +375,7 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
|
||||
{
|
||||
char connectdomain[2048];
|
||||
int connectport;
|
||||
char *domain;
|
||||
const char * domain;
|
||||
|
||||
conn->type = XMPP_CLIENT;
|
||||
|
||||
@@ -434,6 +448,21 @@ void conn_disconnect(xmpp_conn_t * const conn)
|
||||
conn->stream_error, conn->userdata);
|
||||
}
|
||||
|
||||
/* prepares a parser reset. this is called from handlers. we can't
|
||||
* reset the parser immediately as it is not re-entrant. */
|
||||
void conn_prepare_reset(xmpp_conn_t * const conn, xmpp_open_handler handler)
|
||||
{
|
||||
conn->reset_parser = 1;
|
||||
conn->open_handler = handler;
|
||||
}
|
||||
|
||||
/* reset the parser */
|
||||
void conn_parser_reset(xmpp_conn_t * const conn)
|
||||
{
|
||||
conn->reset_parser = 0;
|
||||
parser_reset(conn->parser);
|
||||
}
|
||||
|
||||
/* timed handler for cleanup if normal disconnect procedure takes too long */
|
||||
static int _disconnect_cleanup(xmpp_conn_t * const conn,
|
||||
void * const userdata)
|
||||
@@ -607,3 +636,97 @@ void conn_open_stream(xmpp_conn_t * const conn)
|
||||
conn->type == XMPP_CLIENT ? XMPP_NS_CLIENT : XMPP_NS_COMPONENT,
|
||||
XMPP_NS_STREAMS);
|
||||
}
|
||||
|
||||
static void _log_open_tag(xmpp_conn_t *conn, char **attrs)
|
||||
{
|
||||
char buf[4096];
|
||||
size_t len, pos;
|
||||
int i;
|
||||
|
||||
if (!attrs) return;
|
||||
|
||||
pos = 0;
|
||||
len = xmpp_snprintf(buf, 4096, "<stream:stream");
|
||||
if (len < 0) return;
|
||||
|
||||
pos += len;
|
||||
|
||||
for (i = 0; attrs[i]; i += 2) {
|
||||
len = xmpp_snprintf(&buf[pos], 4096 - pos, " %s='%s'",
|
||||
attrs[i], attrs[i+1]);
|
||||
if (len < 0) return;
|
||||
pos += len;
|
||||
}
|
||||
|
||||
len = xmpp_snprintf(&buf[pos], 4096 - pos, ">");
|
||||
if (len < 0) return;
|
||||
|
||||
xmpp_debug(conn->ctx, "xmpp", "RECV: %s", buf);
|
||||
}
|
||||
|
||||
static char *_get_stream_attribute(char **attrs, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!attrs) return NULL;
|
||||
|
||||
for (i = 0; attrs[i]; i += 2)
|
||||
if (strcmp(name, attrs[i]) == 0)
|
||||
return attrs[i+1];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _handle_stream_start(char *name, char **attrs,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
||||
char *id;
|
||||
|
||||
if (strcmp(name, "stream:stream") != 0) {
|
||||
printf("name = %s\n", name);
|
||||
xmpp_error(conn->ctx, "conn", "Server did not open valid stream.");
|
||||
conn_disconnect(conn);
|
||||
} else {
|
||||
_log_open_tag(conn, attrs);
|
||||
|
||||
if (conn->stream_id) xmpp_free(conn->ctx, conn->stream_id);
|
||||
|
||||
id = _get_stream_attribute(attrs, "id");
|
||||
if (id)
|
||||
conn->stream_id = xmpp_strdup(conn->ctx, id);
|
||||
|
||||
if (!conn->stream_id) {
|
||||
xmpp_error(conn->ctx, "conn", "Memory allocation failed.");
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
}
|
||||
|
||||
/* call stream open handler */
|
||||
conn->open_handler(conn);
|
||||
}
|
||||
|
||||
static void _handle_stream_end(char *name,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
||||
|
||||
/* stream is over */
|
||||
xmpp_debug(conn->ctx, "xmpp", "RECV: </stream:stream>");
|
||||
conn_disconnect_clean(conn);
|
||||
}
|
||||
|
||||
static void _handle_stream_stanza(xmpp_stanza_t *stanza,
|
||||
void * const userdata)
|
||||
{
|
||||
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
||||
char *buf;
|
||||
size_t len;
|
||||
|
||||
if (xmpp_stanza_to_text(stanza, &buf, &len) == 0) {
|
||||
xmpp_debug(conn->ctx, "xmpp", "RECV: %s", buf);
|
||||
xmpp_free(conn->ctx, buf);
|
||||
}
|
||||
|
||||
handler_fire_stanza(conn, stanza);
|
||||
}
|
||||
|
||||
@@ -47,8 +47,9 @@
|
||||
#define ECONNABORTED WSAECONNABORTED
|
||||
#endif
|
||||
|
||||
#include "strophe.h"
|
||||
#include <strophe.h>
|
||||
#include "common.h"
|
||||
#include "parser.h"
|
||||
|
||||
#ifndef DEFAULT_TIMEOUT
|
||||
/** @def DEFAULT_TIMEOUT
|
||||
@@ -168,7 +169,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
||||
/* reset parsers if needed */
|
||||
for (connitem = ctx->connlist; connitem; connitem = connitem->next) {
|
||||
if (connitem->conn->reset_parser)
|
||||
parser_reset(connitem->conn);
|
||||
conn_parser_reset(connitem->conn);
|
||||
}
|
||||
|
||||
|
||||
@@ -267,7 +268,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
ret = XML_Parse(conn->parser, buf, ret, 0);
|
||||
ret = parser_feed(conn->parser, buf, ret);
|
||||
if (!ret) {
|
||||
/* parse error, we need to shut down */
|
||||
/* FIXME */
|
||||
|
||||
206
src/parser.c
206
src/parser.c
@@ -1,206 +0,0 @@
|
||||
/* parser.c
|
||||
** strophe XMPP client library -- xml parser handlers and utility functions
|
||||
**
|
||||
** Copyright (C) 2005-2008 OGG, LLC. All rights reserved.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express
|
||||
** or implied.
|
||||
**
|
||||
** This software is distributed under license and may not be copied,
|
||||
** modified or distributed except as expressly authorized under the
|
||||
** terms of the license contained in the file LICENSE.txt in this
|
||||
** distribution.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* XML parser handlers.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "expat.h"
|
||||
|
||||
#include "strophe.h"
|
||||
#include "common.h"
|
||||
|
||||
static void _log_open_tag(xmpp_conn_t * const conn,
|
||||
const XML_Char **attr)
|
||||
{
|
||||
char buf[4096];
|
||||
size_t len, pos;
|
||||
int i;
|
||||
|
||||
pos = 0;
|
||||
len = xmpp_snprintf(buf, 4096, "<stream:stream");
|
||||
if (len < 0) return;
|
||||
|
||||
pos += len;
|
||||
|
||||
for (i = 0; attr[i]; i += 2) {
|
||||
len = xmpp_snprintf(&buf[pos], 4096 - pos, " %s=\"%s\"",
|
||||
attr[i], attr[i+1]);
|
||||
if (len < 0) return;
|
||||
|
||||
pos += len;
|
||||
}
|
||||
|
||||
len = xmpp_snprintf(&buf[pos], 4096 - pos, ">");
|
||||
if (len < 0) return;
|
||||
|
||||
xmpp_debug(conn->ctx, "xmpp", "RECV: %s", buf);
|
||||
}
|
||||
|
||||
void parser_handle_start(void *userdata,
|
||||
const XML_Char *name,
|
||||
const XML_Char **attr)
|
||||
{
|
||||
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
||||
xmpp_stanza_t *child;
|
||||
|
||||
if (conn->depth == 0) {
|
||||
/* we're expecting a stream:stream tag. */
|
||||
if (strcmp(name, "stream:stream") != 0) {
|
||||
xmpp_error(conn->ctx, "xmpp",
|
||||
"Server did not open valid stream.");
|
||||
conn_disconnect(conn);
|
||||
} else {
|
||||
_log_open_tag(conn, attr);
|
||||
|
||||
if (conn->stream_id) xmpp_free(conn->ctx, conn->stream_id);
|
||||
conn->stream_id = xmpp_strdup(conn->ctx, "foo");
|
||||
if (!conn->stream_id) {
|
||||
xmpp_error(conn->ctx, "xmpp",
|
||||
"Memory allocation failure.");
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
|
||||
/* call stream open handler */
|
||||
conn->open_handler(conn);
|
||||
}
|
||||
} else {
|
||||
/* build stanzas at depth 1 */
|
||||
if (!conn->stanza && conn->depth != 1) {
|
||||
/* something terrible happened */
|
||||
/* FIXME: shutdown disconnect */
|
||||
xmpp_debug(conn->ctx, "xmpp", "oops, where did our stanza go?");
|
||||
} else if (!conn->stanza) {
|
||||
/* starting a new toplevel stanza */
|
||||
conn->stanza = xmpp_stanza_new(conn->ctx);
|
||||
if (!conn->stanza) {
|
||||
/* FIXME: can't allocate, disconnect */
|
||||
}
|
||||
xmpp_stanza_set_name(conn->stanza, name);
|
||||
xmpp_stanza_set_attributes(conn->stanza, attr);
|
||||
} else {
|
||||
/* starting a child of conn->stanza */
|
||||
child = xmpp_stanza_new(conn->ctx);
|
||||
if (!child) {
|
||||
/* FIXME: can't allocate, disconnect */
|
||||
}
|
||||
xmpp_stanza_set_name(child, name);
|
||||
xmpp_stanza_set_attributes(child, attr);
|
||||
|
||||
/* add child to parent */
|
||||
xmpp_stanza_add_child(conn->stanza, child);
|
||||
|
||||
/* the child is owned by the toplevel stanza now */
|
||||
xmpp_stanza_release(child);
|
||||
|
||||
/* make child the current stanza */
|
||||
conn->stanza = child;
|
||||
}
|
||||
}
|
||||
|
||||
conn->depth++;
|
||||
}
|
||||
|
||||
void parser_handle_end(void *userdata, const XML_Char *name)
|
||||
{
|
||||
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
||||
char *buf;
|
||||
size_t len;
|
||||
xmpp_stanza_t *stanza;
|
||||
|
||||
conn->depth--;
|
||||
|
||||
if (conn->depth == 0) {
|
||||
/* got a closing stream tag */
|
||||
xmpp_debug(conn->ctx, "xmpp", "RECV: </stream:stream>");
|
||||
conn_disconnect_clean(conn);
|
||||
} else {
|
||||
if (conn->stanza->parent) {
|
||||
/* we're finishing a child stanza, so set current to the parent */
|
||||
conn->stanza = conn->stanza->parent;
|
||||
} else {
|
||||
/* we're finishing a toplevel stanza, so fire off handler */
|
||||
if (xmpp_stanza_to_text(conn->stanza, &buf, &len) == 0) {
|
||||
xmpp_debug(conn->ctx, "xmpp", "RECV: %s", buf);
|
||||
xmpp_free(conn->ctx, buf);
|
||||
}
|
||||
|
||||
stanza = xmpp_stanza_clone(conn->stanza);
|
||||
xmpp_stanza_release(conn->stanza);
|
||||
conn->stanza = NULL;
|
||||
|
||||
/* fire handlers */
|
||||
handler_fire_stanza(conn, stanza);
|
||||
|
||||
xmpp_stanza_release(stanza);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void parser_handle_character(void *userdata, const XML_Char *s, int len)
|
||||
{
|
||||
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
||||
xmpp_stanza_t *stanza;
|
||||
|
||||
if (conn->depth < 2) return;
|
||||
|
||||
/* create and populate stanza */
|
||||
stanza = xmpp_stanza_new(conn->ctx);
|
||||
if (!stanza) {
|
||||
/* FIXME: allocation error, disconnect */
|
||||
return;
|
||||
}
|
||||
xmpp_stanza_set_text_with_size(stanza, s, len);
|
||||
|
||||
xmpp_stanza_add_child(conn->stanza, stanza);
|
||||
xmpp_stanza_release(stanza);
|
||||
}
|
||||
|
||||
/* prepares a parser reset. this is called from handlers. we can't
|
||||
* reset the parser immediately as it is not reentrant. */
|
||||
void parser_prepare_reset(xmpp_conn_t * const conn,
|
||||
xmpp_open_handler handler)
|
||||
{
|
||||
conn->reset_parser = 1;
|
||||
conn->open_handler = handler;
|
||||
}
|
||||
|
||||
/* shuts down and restarts XML parser. true on success */
|
||||
int parser_reset(xmpp_conn_t * const conn)
|
||||
{
|
||||
conn->reset_parser = 0;
|
||||
|
||||
if (conn->parser)
|
||||
XML_ParserFree(conn->parser);
|
||||
|
||||
if (conn->stanza)
|
||||
xmpp_stanza_release(conn->stanza);
|
||||
|
||||
conn->parser = XML_ParserCreate(NULL);
|
||||
if (!conn->parser) return 0;
|
||||
|
||||
conn->depth = 0;
|
||||
conn->stanza = NULL;
|
||||
XML_SetUserData(conn->parser, conn);
|
||||
XML_SetElementHandler(conn->parser, parser_handle_start,
|
||||
parser_handle_end);
|
||||
XML_SetCharacterDataHandler(conn->parser, parser_handle_character);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
43
src/parser.h
Normal file
43
src/parser.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* parser.h
|
||||
** strophe XMPP client library -- parser structures and functions
|
||||
**
|
||||
** Copyright (C) 2005-2009 Stanziq, Inc. All rights reserved.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express or
|
||||
** implied.
|
||||
**
|
||||
** This software is distributed under license and may not be copied,
|
||||
** modified or distributed except as expressly authorized under the
|
||||
** terms of the license contained in the file LICENSE.txt in this
|
||||
** distribution.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* Internally used functions and structures.
|
||||
*/
|
||||
|
||||
#ifndef __LIBSTROPHE_PARSER_H__
|
||||
#define __LIBSTROPHE_PARSER_H__
|
||||
|
||||
#include "strophe.h"
|
||||
|
||||
typedef struct _parser_t parser_t;
|
||||
|
||||
typedef void (*parser_start_callback)(char *name,
|
||||
char **attrs,
|
||||
void * const userdata);
|
||||
typedef void (*parser_end_callback)(char *name, void * const userdata);
|
||||
typedef void (*parser_stanza_callback)(xmpp_stanza_t *stanza,
|
||||
void * const userdata);
|
||||
|
||||
|
||||
parser_t *parser_new(xmpp_ctx_t *ctx,
|
||||
parser_start_callback startcb,
|
||||
parser_end_callback endcb,
|
||||
parser_stanza_callback stanzacb,
|
||||
void *userdata);
|
||||
void parser_free(parser_t * const parser);
|
||||
int parser_reset(parser_t *parser);
|
||||
int parser_feed(parser_t *parser, char *chunk, int len);
|
||||
|
||||
#endif /* __LIBSTROPHE_PARSER_H__ */
|
||||
202
src/parser_expat.c
Normal file
202
src/parser_expat.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/* parser.c
|
||||
** strophe XMPP client library -- xml parser handlers and utility functions
|
||||
**
|
||||
** Copyright (C) 2005-2008 OGG, LLC. All rights reserved.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express
|
||||
** or implied.
|
||||
**
|
||||
** This software is distributed under license and may not be copied,
|
||||
** modified or distributed except as expressly authorized under the
|
||||
** terms of the license contained in the file LICENSE.txt in this
|
||||
** distribution.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* XML parser handlers.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <expat.h>
|
||||
|
||||
#include <strophe.h>
|
||||
#include "common.h"
|
||||
#include "parser.h"
|
||||
|
||||
struct _parser_t {
|
||||
xmpp_ctx_t *ctx;
|
||||
XML_Parser expat;
|
||||
parser_start_callback startcb;
|
||||
parser_end_callback endcb;
|
||||
parser_stanza_callback stanzacb;
|
||||
void *userdata;
|
||||
int depth;
|
||||
xmpp_stanza_t *stanza;
|
||||
};
|
||||
|
||||
static void _set_attributes(xmpp_stanza_t *stanza, const XML_Char **attrs)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!attrs) return;
|
||||
|
||||
for (i = 0; attrs[i]; i += 2) {
|
||||
xmpp_stanza_set_attribute(stanza, attrs[i], attrs[i+1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void _start_element(void *userdata,
|
||||
const XML_Char *name,
|
||||
const XML_Char **attrs)
|
||||
{
|
||||
parser_t *parser = (parser_t *)userdata;
|
||||
xmpp_stanza_t *child;
|
||||
|
||||
if (parser->depth == 0) {
|
||||
/* notify the owner */
|
||||
if (parser->startcb)
|
||||
parser->startcb((char *)name, (char **)attrs,
|
||||
parser->userdata);
|
||||
} else {
|
||||
/* build stanzas at depth 1 */
|
||||
if (!parser->stanza && parser->depth != 1) {
|
||||
/* something terrible happened */
|
||||
/* FIXME: shutdown disconnect */
|
||||
xmpp_error(parser->ctx, "parser", "oops, where did our stanza go?");
|
||||
} else if (!parser->stanza) {
|
||||
/* starting a new toplevel stanza */
|
||||
parser->stanza = xmpp_stanza_new(parser->ctx);
|
||||
if (!parser->stanza) {
|
||||
/* FIXME: can't allocate, disconnect */
|
||||
}
|
||||
xmpp_stanza_set_name(parser->stanza, name);
|
||||
_set_attributes(parser->stanza, attrs);
|
||||
} else {
|
||||
/* starting a child of parser->stanza */
|
||||
child = xmpp_stanza_new(parser->ctx);
|
||||
if (!child) {
|
||||
/* FIXME: can't allocate, disconnect */
|
||||
}
|
||||
xmpp_stanza_set_name(child, name);
|
||||
_set_attributes(child, attrs);
|
||||
|
||||
/* add child to parent */
|
||||
xmpp_stanza_add_child(parser->stanza, child);
|
||||
|
||||
/* the child is owned by the toplevel stanza now */
|
||||
xmpp_stanza_release(child);
|
||||
|
||||
/* make child the current stanza */
|
||||
parser->stanza = child;
|
||||
}
|
||||
}
|
||||
|
||||
parser->depth++;
|
||||
}
|
||||
|
||||
static void _end_element(void *userdata, const XML_Char *name)
|
||||
{
|
||||
parser_t *parser = (parser_t *)userdata;
|
||||
|
||||
parser->depth--;
|
||||
|
||||
if (parser->depth == 0) {
|
||||
/* notify the owner */
|
||||
if (parser->endcb)
|
||||
parser->endcb((char *)name, parser->userdata);
|
||||
} else {
|
||||
if (parser->stanza->parent) {
|
||||
/* we're finishing a child stanza, so set current to the parent */
|
||||
parser->stanza = parser->stanza->parent;
|
||||
} else {
|
||||
if (parser->stanzacb)
|
||||
parser->stanzacb(xmpp_stanza_clone(parser->stanza),
|
||||
parser->userdata);
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
parser->stanza = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _characters(void *userdata, const XML_Char *s, int len)
|
||||
{
|
||||
parser_t *parser = (parser_t *)userdata;
|
||||
xmpp_stanza_t *stanza;
|
||||
|
||||
if (parser->depth < 2) return;
|
||||
|
||||
/* create and populate stanza */
|
||||
stanza = xmpp_stanza_new(parser->ctx);
|
||||
if (!stanza) {
|
||||
/* FIXME: allocation error, disconnect */
|
||||
return;
|
||||
}
|
||||
xmpp_stanza_set_text_with_size(stanza, s, len);
|
||||
|
||||
xmpp_stanza_add_child(parser->stanza, stanza);
|
||||
xmpp_stanza_release(stanza);
|
||||
}
|
||||
|
||||
parser_t *parser_new(xmpp_ctx_t *ctx,
|
||||
parser_start_callback startcb,
|
||||
parser_end_callback endcb,
|
||||
parser_stanza_callback stanzacb,
|
||||
void *userdata)
|
||||
{
|
||||
parser_t *parser;
|
||||
|
||||
parser = xmpp_alloc(ctx, sizeof(parser_t));
|
||||
if (parser != NULL) {
|
||||
parser->ctx = ctx;
|
||||
parser->expat = NULL;
|
||||
parser->startcb = startcb;
|
||||
parser->endcb = endcb;
|
||||
parser->stanzacb = stanzacb;
|
||||
parser->userdata = userdata;
|
||||
parser->depth = 0;
|
||||
parser->stanza = NULL;
|
||||
|
||||
parser_reset(parser);
|
||||
}
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
/* free a parser */
|
||||
void parser_free(parser_t *parser)
|
||||
{
|
||||
if (parser->expat)
|
||||
XML_ParserFree(parser->expat);
|
||||
|
||||
xmpp_free(parser->ctx, parser);
|
||||
}
|
||||
|
||||
/* shuts down and restarts XML parser. true on success */
|
||||
int parser_reset(parser_t *parser)
|
||||
{
|
||||
if (parser->expat)
|
||||
XML_ParserFree(parser->expat);
|
||||
|
||||
if (parser->stanza)
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
|
||||
parser->expat = XML_ParserCreate(NULL);
|
||||
if (!parser->expat) return 0;
|
||||
|
||||
parser->depth = 0;
|
||||
parser->stanza = NULL;
|
||||
|
||||
XML_SetUserData(parser->expat, parser);
|
||||
XML_SetElementHandler(parser->expat, _start_element, _end_element);
|
||||
XML_SetCharacterDataHandler(parser->expat, _characters);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parser_feed(parser_t *parser, char *chunk, int len)
|
||||
{
|
||||
return XML_Parse(parser->expat, chunk, len, 0);
|
||||
}
|
||||
206
src/parser_libxml2.c
Normal file
206
src/parser_libxml2.c
Normal file
@@ -0,0 +1,206 @@
|
||||
/* parser.c
|
||||
** strophe XMPP client library -- xml parser handlers and utility functions
|
||||
**
|
||||
** Copyright (C) 2005-2008 OGG, LLC. All rights reserved.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express
|
||||
** or implied.
|
||||
**
|
||||
** This software is distributed under license and may not be copied,
|
||||
** modified or distributed except as expressly authorized under the
|
||||
** terms of the license contained in the file LICENSE.txt in this
|
||||
** distribution.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* XML parser handlers.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
|
||||
#include <strophe.h>
|
||||
#include "common.h"
|
||||
#include "parser.h"
|
||||
|
||||
struct _parser_t {
|
||||
xmpp_ctx_t *ctx;
|
||||
xmlParserCtxtPtr xmlctx;
|
||||
xmlSAXHandler handlers;
|
||||
parser_start_callback startcb;
|
||||
parser_end_callback endcb;
|
||||
parser_stanza_callback stanzacb;
|
||||
void *userdata;
|
||||
int depth;
|
||||
xmpp_stanza_t *stanza;
|
||||
};
|
||||
|
||||
static void _set_attributes(xmpp_stanza_t *stanza, const xmlChar **attrs)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!attrs) return;
|
||||
|
||||
for (i = 0; attrs[i]; i += 2) {
|
||||
xmpp_stanza_set_attribute(stanza, attrs[i], attrs[i+1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void _start_element(void *userdata,
|
||||
const xmlChar *name, const xmlChar **attrs)
|
||||
{
|
||||
parser_t *parser = (parser_t *)userdata;
|
||||
xmpp_stanza_t *child;
|
||||
|
||||
if (parser->depth == 0) {
|
||||
/* notify the owner */
|
||||
if (parser->startcb)
|
||||
parser->startcb((char *)name, (char **)attrs,
|
||||
parser->userdata);
|
||||
} else {
|
||||
/* build stanzas at depth 1 */
|
||||
if (!parser->stanza && parser->depth != 1) {
|
||||
/* something terrible happened */
|
||||
/* FIXME: we should probably trigger a disconnect */
|
||||
xmpp_error(parser->ctx, "parser", "oops, where did our stanza go?");
|
||||
} else if (!parser->stanza) {
|
||||
/* starting a new toplevel stanza */
|
||||
parser->stanza = xmpp_stanza_new(parser->ctx);
|
||||
if (!parser->stanza) {
|
||||
/* FIXME: can't allocate, disconnect */
|
||||
}
|
||||
xmpp_stanza_set_name(parser->stanza, (char *)name);
|
||||
_set_attributes(parser->stanza, attrs);
|
||||
} else {
|
||||
/* starting a child of conn->stanza */
|
||||
child = xmpp_stanza_new(parser->ctx);
|
||||
if (!child) {
|
||||
/* FIXME: can't allocate, disconnect */
|
||||
}
|
||||
xmpp_stanza_set_name(child, (char *)name);
|
||||
_set_attributes(child, attrs);
|
||||
|
||||
/* add child to parent */
|
||||
xmpp_stanza_add_child(parser->stanza, child);
|
||||
|
||||
/* the child is owned by the toplevel stanza now */
|
||||
xmpp_stanza_release(child);
|
||||
|
||||
/* make child the current stanza */
|
||||
parser->stanza = child;
|
||||
}
|
||||
}
|
||||
|
||||
parser->depth++;
|
||||
}
|
||||
|
||||
static void _end_element(void *userdata, const xmlChar *name)
|
||||
{
|
||||
parser_t *parser = (parser_t *)userdata;
|
||||
|
||||
parser->depth--;
|
||||
|
||||
if (parser->depth == 0) {
|
||||
/* notify owner */
|
||||
if (parser->endcb)
|
||||
parser->endcb((char *)name, parser->userdata);
|
||||
} else {
|
||||
if (parser->stanza->parent) {
|
||||
/* we're finishing a child stanza, so set current to the parent */
|
||||
parser->stanza = parser->stanza->parent;
|
||||
} else {
|
||||
if (parser->stanzacb)
|
||||
parser->stanzacb(xmpp_stanza_clone(parser->stanza),
|
||||
parser->userdata);
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
parser->stanza = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _characters(void *userdata, const xmlChar *chr, int len)
|
||||
{
|
||||
parser_t *parser = (parser_t *)userdata;
|
||||
xmpp_stanza_t *stanza;
|
||||
|
||||
/* skip unimportant whitespace, etc */
|
||||
if (parser->depth < 2) return;
|
||||
|
||||
/* create and populate stanza */
|
||||
stanza = xmpp_stanza_new(parser->ctx);
|
||||
if (!stanza) {
|
||||
/* FIXME: allocation error, disconnect */
|
||||
return;
|
||||
}
|
||||
xmpp_stanza_set_text_with_size(stanza, (char *)chr, len);
|
||||
|
||||
xmpp_stanza_add_child(parser->stanza, stanza);
|
||||
xmpp_stanza_release(stanza);
|
||||
}
|
||||
|
||||
/* create a new parser */
|
||||
parser_t *parser_new(xmpp_ctx_t *ctx,
|
||||
parser_start_callback startcb,
|
||||
parser_end_callback endcb,
|
||||
parser_stanza_callback stanzacb,
|
||||
void *userdata)
|
||||
{
|
||||
parser_t *parser;
|
||||
|
||||
parser = xmpp_alloc(ctx, sizeof(parser_t));
|
||||
if (parser != NULL) {
|
||||
parser->ctx = ctx;
|
||||
parser->xmlctx = NULL;
|
||||
memset(&parser->handlers, 0, sizeof(xmlSAXHandler));
|
||||
parser->handlers.startElement = _start_element;
|
||||
parser->handlers.endElement = _end_element;
|
||||
parser->handlers.characters = _characters;
|
||||
parser->startcb = startcb;
|
||||
parser->endcb = endcb;
|
||||
parser->stanzacb = stanzacb;
|
||||
parser->userdata = userdata;
|
||||
parser->depth = 0;
|
||||
parser->stanza = NULL;
|
||||
|
||||
parser_reset(parser);
|
||||
}
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
/* free a parser */
|
||||
void parser_free(parser_t *parser)
|
||||
{
|
||||
if (parser->xmlctx)
|
||||
xmlFreeParserCtxt(parser->xmlctx);
|
||||
xmpp_free(parser->ctx, parser);
|
||||
}
|
||||
|
||||
/* shuts down and restarts XML parser. true on success */
|
||||
int parser_reset(parser_t *parser)
|
||||
{
|
||||
if (parser->xmlctx)
|
||||
xmlFreeParserCtxt(parser->xmlctx);
|
||||
|
||||
if (parser->stanza)
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
|
||||
parser->xmlctx = xmlCreatePushParserCtxt(&parser->handlers,
|
||||
parser, NULL, 0, NULL);
|
||||
if (!parser->xmlctx) return 0;
|
||||
|
||||
parser->depth = 0;
|
||||
parser->stanza = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* feed a chunk of data to the parser */
|
||||
int parser_feed(parser_t *parser, char *chunk, int len)
|
||||
{
|
||||
return xmlParseChunk(parser->xmlctx, chunk, len, 0);
|
||||
}
|
||||
39
src/stanza.c
39
src/stanza.c
@@ -400,45 +400,6 @@ char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza)
|
||||
return stanza->data;
|
||||
}
|
||||
|
||||
/** Set or replace attributes on a stanza.
|
||||
* This function replaces all previous attributes (if any) with the
|
||||
* attributes given. It is used primarily by the XML parser during
|
||||
* stanza creation. All strings in the array are copied before placing them
|
||||
* inside the stanza object.
|
||||
*
|
||||
* @param stanza a Strophe stanza object
|
||||
* @param attr an array of strings with the attributes in the following
|
||||
* format: attr[i] = attribute name, attr[i+1] = attribute value
|
||||
*
|
||||
* @return XMPP_EOK on success, a number less than 0 on failure (XMPP_EMEM,
|
||||
* XMPP_EINVOP)
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
int xmpp_stanza_set_attributes(xmpp_stanza_t * const stanza,
|
||||
const char * const * const attr)
|
||||
{
|
||||
int i;
|
||||
char *value;
|
||||
|
||||
if (stanza->attributes != NULL)
|
||||
hash_release(stanza->attributes);
|
||||
|
||||
stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free);
|
||||
if (!stanza->attributes) return XMPP_EMEM;
|
||||
|
||||
for (i = 0; attr[i]; i += 2) {
|
||||
value = xmpp_strdup(stanza->ctx, attr[i + 1]);
|
||||
if (!value) {
|
||||
/* FIXME: memory allocation error */
|
||||
continue;
|
||||
}
|
||||
hash_add(stanza->attributes, attr[i], value);
|
||||
}
|
||||
|
||||
return XMPP_EOK;
|
||||
}
|
||||
|
||||
/** Count the attributes in a stanza object.
|
||||
*
|
||||
* @param stanza a Strophe stanza object
|
||||
|
||||
93
tests/check_parser.c
Normal file
93
tests/check_parser.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/* check_parser.h
|
||||
** strophe XMPP client library -- parser tests
|
||||
**
|
||||
** Copyright (C) 2005-2009 Stanziq, Inc. All rights reserved.
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express or
|
||||
** implied.
|
||||
**
|
||||
** This software is distributed under license and may not be copied,
|
||||
** modified or distributed except as expressly authorized under the
|
||||
** terms of the license contained in the file LICENSE.txt in this
|
||||
** distribution.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <check.h>
|
||||
|
||||
#include <strophe.h>
|
||||
#include "parser.h"
|
||||
|
||||
#include "test.h"
|
||||
|
||||
START_TEST(create_destroy)
|
||||
{
|
||||
xmpp_ctx_t *ctx;
|
||||
parser_t *parser;
|
||||
|
||||
ctx = xmpp_ctx_new(NULL, NULL);
|
||||
parser = parser_new(ctx, NULL, NULL, NULL, NULL);
|
||||
fail_unless(parser != NULL, "Parser creation failed.");
|
||||
parser_free(parser);
|
||||
xmpp_ctx_free(ctx);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
int cbtest_got_start = 0;
|
||||
void cbtest_handle_start(char *name, char **attrs, void *userdata)
|
||||
{
|
||||
if (strcmp(name, "stream:stream") == 0)
|
||||
cbtest_got_start = 1;
|
||||
}
|
||||
|
||||
int cbtest_got_end = 0;
|
||||
void cbtest_handle_end(char *name, void *userdata)
|
||||
{
|
||||
if (strcmp(name, "stream:stream") == 0)
|
||||
cbtest_got_end = 1;
|
||||
}
|
||||
|
||||
int cbtest_got_stanza = 0;
|
||||
void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata)
|
||||
{
|
||||
if (strcmp(xmpp_stanza_get_name(stanza), "message") == 0)
|
||||
cbtest_got_stanza = 1;
|
||||
}
|
||||
|
||||
START_TEST(callbacks)
|
||||
{
|
||||
xmpp_ctx_t *ctx;
|
||||
parser_t *parser;
|
||||
int ret;
|
||||
|
||||
ctx = xmpp_ctx_new(NULL, NULL);
|
||||
parser = parser_new(ctx,
|
||||
cbtest_handle_start,
|
||||
cbtest_handle_end,
|
||||
cbtest_handle_stanza, NULL);
|
||||
|
||||
ret = parser_feed(parser, "<stream:stream>", 15);
|
||||
ret = parser_feed(parser, "<message/>", 10);
|
||||
parser_feed(parser, "</stream:stream>", 16);
|
||||
|
||||
fail_unless(cbtest_got_start == 1);
|
||||
fail_unless(cbtest_got_end == 1);
|
||||
fail_unless(cbtest_got_stanza == 1);
|
||||
|
||||
parser_free(parser);
|
||||
xmpp_ctx_free(ctx);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *parser_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("Parser");
|
||||
TCase *tc_core = tcase_create("Core");
|
||||
tcase_add_test(tc_core, create_destroy);
|
||||
tcase_add_test(tc_core, callbacks);
|
||||
suite_add_tcase(s, tc_core);
|
||||
return s;
|
||||
}
|
||||
|
||||
TEST_MAIN
|
||||
16
tests/test.h
Normal file
16
tests/test.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef __LIBSTROPHE_TEST_H__
|
||||
#define __LIBSTROPHE_TEST_H__
|
||||
|
||||
#define TEST_MAIN \
|
||||
int main(int argc, char **argv) {\
|
||||
int num_failed;\
|
||||
Suite *s = parser_suite();\
|
||||
SRunner *sr = srunner_create(s);\
|
||||
srunner_run_all(sr, CK_NORMAL);\
|
||||
num_failed = srunner_ntests_failed(sr);\
|
||||
srunner_free(sr);\
|
||||
return (num_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\
|
||||
}\
|
||||
|
||||
|
||||
#endif /* __LIBSTROPHE_TEST_H__ */
|
||||
Reference in New Issue
Block a user