#include <jabberd.h>
void _mio_xstream_startElement(mio m, const char* name, const char** attribs)
{
if (m->stacknode == NULL)
{
pool p = pool_heap(5 * 1024);
m->stacknode = xmlnode_new_tag_pool(p, name);
xmlnode_put_expat_attribs(m->stacknode, attribs);
if (m->root == 0)
{
if(m->cb != NULL)
(*(mio_xml_cb)m->cb)(m, MIO_XML_ROOT, m->cb_arg, m->stacknode);
else
xmlnode_free(m->stacknode);
m->stacknode = NULL;
m->root = 1;
}
}
else
{
m->stacknode = xmlnode_insert_tag(m->stacknode, name);
xmlnode_put_expat_attribs(m->stacknode, attribs);
}
if (xmlnode_get_parent(m->stacknode) == NULL)
{
log_debug("mio", "[%s] _mio_xstream_startElement(name=%s) new stanza", ZONE, name);
m->message = !strcmp(name, "message");
m->bytes_read = 0;
}
}
void _mio_xstream_endElement(mio m, const char* name)
{
if (m->stacknode == NULL)
{
mio_close(m);
}
else
{
xmlnode parent = xmlnode_get_parent(m->stacknode);
if (parent == NULL)
{
if(m->cb != NULL)
(*(mio_xml_cb)m->cb)(m, MIO_XML_NODE, m->cb_arg, m->stacknode);
else
xmlnode_free(m->stacknode);
}
m->stacknode = parent;
}
}
void _mio_xstream_CDATA(mio m, const char* cdata, int len)
{
if (m->stacknode != NULL)
xmlnode_insert_cdata(m->stacknode, cdata, len);
}
void _mio_xstream_cleanup(void* arg)
{
mio m = (void*)arg;
xmlnode_free(m->stacknode);
XML_ParserFree(m->parser);
m->parser = NULL;
}
void _mio_xstream_init(mio m)
{
if (m != NULL)
{
m->parser = XML_ParserCreate(NULL);
XML_SetUserData(m->parser, m);
XML_SetElementHandler(m->parser, (void*)_mio_xstream_startElement, (void*)_mio_xstream_endElement);
XML_SetCharacterDataHandler(m->parser, (void*)_mio_xstream_CDATA);
pool_cleanup(m->p, _mio_xstream_cleanup, (void*)m);
}
}
void _mio_xml_parser(mio m, const void *vbuf, size_t bufsz)
{
char *nul, *buf = (char*)vbuf;
enum XML_Status result;
if(m->parser == NULL)
{
_mio_xstream_init(m);
if((nul = strchr(buf,'\0')) != NULL && (nul - buf) < bufsz)
{
m->type = type_NUL;
nul[-2] = ' ';
}
if(*buf == 'P')
m->type = type_HTTP;
}
if(m->type == type_HTTP)
{
if((nul = strstr(buf,"\r\n\r\n")) == NULL)
return;
nul += 4;
bufsz = bufsz - (nul - buf);
buf = nul;
mio_write(m,NULL,"HTTP/1.0 200 Ok\r\nServer: jabber/xmlstream-hack-0.1\r\nExpires: Fri, 10 Oct 1997 10:10:10 GMT\r\nPragma: no-cache\r\nCache-control: private\r\nConnection: close\r\n\r\n",-1);
m->type = type_NORMAL;
}
if(m->type == type_NUL)
while((nul = strchr(buf,'\0')) != NULL && (nul - buf) < bufsz)
{
memmove(nul,nul+1,strlen(nul+1));
bufsz--;
}
result = XML_Parse(m->parser, buf, bufsz, 0);
if(m->cb == NULL)
return;
if(result == XML_STATUS_ERROR)
{
log_error(ZONE, "[%s] XML Parsing Error: %s", XML_ErrorString(XML_GetErrorCode(m->parser)));
(*(mio_std_cb)m->cb)(m, MIO_ERROR, m->cb_arg);
mio_write(m, NULL, "<stream:error>Invalid XML</stream:error>", -1);
mio_close(m);
return;
}
log_debug("mio", "[%s] XML_Parse(bufsz=%d) returned OK", ZONE, bufsz);
if(m->max_stanza_bytes > 0)
{
m->bytes_read += bufsz;
if(m->bytes_read > m->max_stanza_bytes)
{
log_error(ZONE, "Stanza exceeds maximum size; aborting connection on socket %d", m->fd);
(*(mio_std_cb)m->cb)(m, MIO_ERROR, m->cb_arg);
mio_write(m, NULL, "<stream:error>Stanza too large</stream:error>", -1);
mio_close(m);
}
else if(m->message && (m->max_message_bytes > 0) && (m->bytes_read > m->max_message_bytes))
{
log_error(ZONE, "Message exceeds maximum size; aborting connection on socket %d", m->fd);
(*(mio_std_cb)m->cb)(m, MIO_ERROR, m->cb_arg);
mio_write(m, NULL, "<stream:error>Message too large</stream:error>", -1);
mio_close(m);
}
}
}