mirror of
https://forge.fsky.io/lda/Parsee.git
synced 2026-03-13 16:45:10 +00:00
[ADD/WIP] Basic XEP-0393 support.
Still needs lots of work. Did I fail to mention I _hate_ HTML?
This commit is contained in:
parent
94cba7acf0
commit
771c3271ad
10 changed files with 473 additions and 9 deletions
|
|
@ -10,6 +10,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <StringStream.h>
|
||||||
#include <Parsee.h>
|
#include <Parsee.h>
|
||||||
#include <XMPP.h>
|
#include <XMPP.h>
|
||||||
#include <XML.h>
|
#include <XML.h>
|
||||||
|
|
@ -29,6 +30,7 @@ Main(void)
|
||||||
Stream *yaml;
|
Stream *yaml;
|
||||||
Cron *cron = NULL;
|
Cron *cron = NULL;
|
||||||
|
|
||||||
|
memset(&conf, 0, sizeof(conf));
|
||||||
Log(LOG_INFO,
|
Log(LOG_INFO,
|
||||||
"%s - v%s (Cytoplasm %s)",
|
"%s - v%s (Cytoplasm %s)",
|
||||||
NAME, VERSION, CytoplasmGetVersionStr()
|
NAME, VERSION, CytoplasmGetVersionStr()
|
||||||
|
|
@ -66,7 +68,6 @@ Main(void)
|
||||||
ASRegisterUser(parsee_conf, parsee_conf->sender_localpart);
|
ASRegisterUser(parsee_conf, parsee_conf->sender_localpart);
|
||||||
|
|
||||||
|
|
||||||
memset(&conf, 0, sizeof(conf));
|
|
||||||
conf.port = parsee_conf->port;
|
conf.port = parsee_conf->port;
|
||||||
conf.threads = 4;
|
conf.threads = 4;
|
||||||
conf.maxConnections = 32;
|
conf.maxConnections = 32;
|
||||||
|
|
|
||||||
|
|
@ -73,12 +73,14 @@ ParseeMessageHandler(ParseeData *data, HashMap *event)
|
||||||
char *sender = GrabString(event, 1, "sender");
|
char *sender = GrabString(event, 1, "sender");
|
||||||
char *chat_id, *muc_id, *jid;
|
char *chat_id, *muc_id, *jid;
|
||||||
char *reply_id = MatrixGetReply(event);
|
char *reply_id = MatrixGetReply(event);
|
||||||
|
char *xepd = ParseeXMPPify(event);
|
||||||
|
|
||||||
bool direct = false;
|
bool direct = false;
|
||||||
|
|
||||||
if (ParseeIsPuppet(data->config, sender))
|
if (ParseeIsPuppet(data->config, sender))
|
||||||
{
|
{
|
||||||
Free(reply_id);
|
Free(reply_id);
|
||||||
|
Free(xepd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,6 +103,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event)
|
||||||
|
|
||||||
Free(local);
|
Free(local);
|
||||||
Free(reply_id);
|
Free(reply_id);
|
||||||
|
Free(xepd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,6 +113,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event)
|
||||||
if (!chat_id)
|
if (!chat_id)
|
||||||
{
|
{
|
||||||
Free(reply_id);
|
Free(reply_id);
|
||||||
|
Free(xepd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
jid = ParseeEncodeMXID(sender);
|
jid = ParseeEncodeMXID(sender);
|
||||||
|
|
@ -125,7 +129,11 @@ ParseeMessageHandler(ParseeData *data, HashMap *event)
|
||||||
Log(LOG_INFO, "Replying to %s by %s", stanza, sender);
|
Log(LOG_INFO, "Replying to %s by %s", stanza, sender);
|
||||||
}
|
}
|
||||||
XMPPJoinMUC(jabber, jid, rev);
|
XMPPJoinMUC(jabber, jid, rev);
|
||||||
XMPPSendPlain(jabber, jid, muc_id, body, "groupchat", stanza, sender);
|
XMPPSendPlain(
|
||||||
|
jabber, jid, muc_id,
|
||||||
|
xepd ? xepd : body, "groupchat",
|
||||||
|
stanza, sender
|
||||||
|
);
|
||||||
Free(rev);
|
Free(rev);
|
||||||
Free(name);
|
Free(name);
|
||||||
Free(stanza);
|
Free(stanza);
|
||||||
|
|
@ -135,6 +143,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event)
|
||||||
Free(muc_id);
|
Free(muc_id);
|
||||||
Free(jid);
|
Free(jid);
|
||||||
Free(reply_id);
|
Free(reply_id);
|
||||||
|
Free(xepd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -132,3 +132,156 @@ ParseeFindDatastart(char *data)
|
||||||
|
|
||||||
return (int) (startline - data);
|
return (int) (startline - data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <StringStream.h>
|
||||||
|
|
||||||
|
static char *
|
||||||
|
XMPPifyElement(XMLElement *elem)
|
||||||
|
{
|
||||||
|
char *xepd = NULL, *tmp = NULL;
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
XMLElement *child;
|
||||||
|
char *subxep;
|
||||||
|
#define Concat(strp) tmp = xepd; \
|
||||||
|
xepd = StrConcat(2, xepd, strp); \
|
||||||
|
Free(tmp)
|
||||||
|
switch (elem->type)
|
||||||
|
{
|
||||||
|
case XML_ELEMENT_DATA:
|
||||||
|
Concat(elem->data);
|
||||||
|
break;
|
||||||
|
case XML_ELEMENT_TAG:
|
||||||
|
if (StrEquals(elem->name, "b") || StrEquals(elem->name, "strong"))
|
||||||
|
{
|
||||||
|
Concat("*");
|
||||||
|
for (i = 0; i < ArraySize(elem->children); i++)
|
||||||
|
{
|
||||||
|
child = ArrayGet(elem->children, i);
|
||||||
|
subxep = XMPPifyElement(child);
|
||||||
|
|
||||||
|
Concat(subxep);
|
||||||
|
Free(subxep);
|
||||||
|
}
|
||||||
|
Concat("*");
|
||||||
|
}
|
||||||
|
else if (StrEquals(elem->name, "em"))
|
||||||
|
{
|
||||||
|
Concat("_");
|
||||||
|
for (i = 0; i < ArraySize(elem->children); i++)
|
||||||
|
{
|
||||||
|
child = ArrayGet(elem->children, i);
|
||||||
|
subxep = XMPPifyElement(child);
|
||||||
|
|
||||||
|
Concat(subxep);
|
||||||
|
Free(subxep);
|
||||||
|
}
|
||||||
|
Concat("_");
|
||||||
|
}
|
||||||
|
else if (StrEquals(elem->name, "code"))
|
||||||
|
{
|
||||||
|
Concat("`");
|
||||||
|
for (i = 0; i < ArraySize(elem->children); i++)
|
||||||
|
{
|
||||||
|
child = ArrayGet(elem->children, i);
|
||||||
|
subxep = XMPPifyElement(child);
|
||||||
|
|
||||||
|
Concat(subxep);
|
||||||
|
Free(subxep);
|
||||||
|
}
|
||||||
|
Concat("`");
|
||||||
|
}
|
||||||
|
else if (StrEquals(elem->name, "blockquote"))
|
||||||
|
{
|
||||||
|
Concat(">");
|
||||||
|
for (i = 0; i < ArraySize(elem->children); i++)
|
||||||
|
{
|
||||||
|
child = ArrayGet(elem->children, i);
|
||||||
|
subxep = XMPPifyElement(child);
|
||||||
|
|
||||||
|
Concat(subxep);
|
||||||
|
Free(subxep);
|
||||||
|
}
|
||||||
|
Concat("\n");
|
||||||
|
}
|
||||||
|
else if (StrEquals(elem->name, "br"))
|
||||||
|
{
|
||||||
|
Concat("\n");
|
||||||
|
/* HTML fucking SUCKS */
|
||||||
|
for (i = 0; i < ArraySize(elem->children); i++)
|
||||||
|
{
|
||||||
|
child = ArrayGet(elem->children, i);
|
||||||
|
subxep = XMPPifyElement(child);
|
||||||
|
|
||||||
|
Concat(subxep);
|
||||||
|
Free(subxep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (StrEquals(elem->name, "a"))
|
||||||
|
{
|
||||||
|
char *href = HashMapGet(elem->attrs, "href");
|
||||||
|
Concat("(");
|
||||||
|
for (i = 0; i < ArraySize(elem->children); i++)
|
||||||
|
{
|
||||||
|
child = ArrayGet(elem->children, i);
|
||||||
|
subxep = XMPPifyElement(child);
|
||||||
|
|
||||||
|
Concat(subxep);
|
||||||
|
Free(subxep);
|
||||||
|
}
|
||||||
|
Concat(" points to ");
|
||||||
|
Concat(href);
|
||||||
|
Concat(" )");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < ArraySize(elem->children); i++)
|
||||||
|
{
|
||||||
|
child = ArrayGet(elem->children, i);
|
||||||
|
subxep = XMPPifyElement(child);
|
||||||
|
|
||||||
|
Concat(subxep);
|
||||||
|
Free(subxep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return xepd;
|
||||||
|
}
|
||||||
|
char *
|
||||||
|
ParseeXMPPify(HashMap *event)
|
||||||
|
{
|
||||||
|
char *cntr, *type, *format, *html;
|
||||||
|
char *xepd = NULL, *tmp;
|
||||||
|
XMLElement *elem;
|
||||||
|
if (!event)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if it is a message event. */
|
||||||
|
type = JsonValueAsString(HashMapGet(event, "type"));
|
||||||
|
if (!StrEquals(type, "m.room.message"))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
format = JsonValueAsString(JsonGet(event, 2, "content", "format"));
|
||||||
|
if (!StrEquals(format, "org.matrix.custom.html"))
|
||||||
|
{
|
||||||
|
/* Settle for the raw body instead. */
|
||||||
|
char *body = JsonValueAsString(JsonGet(event, 2, "content", "body"));
|
||||||
|
return StrDuplicate(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
html = JsonValueAsString(JsonGet(event, 2, "content", "formatted_body"));
|
||||||
|
html = StrConcat(3, "<html>", html, "</html>");
|
||||||
|
elem = XMLDecode(StrStreamReader(html), true);
|
||||||
|
|
||||||
|
xepd = XMPPifyElement(elem);
|
||||||
|
|
||||||
|
XMLFreeElement(elem);
|
||||||
|
Free(html);
|
||||||
|
|
||||||
|
return xepd;
|
||||||
|
}
|
||||||
|
|
|
||||||
131
src/Streams/Reader.c
Normal file
131
src/Streams/Reader.c
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
#include <StringStream.h>
|
||||||
|
|
||||||
|
#include <Cytoplasm/Memory.h>
|
||||||
|
#include <Cytoplasm/Stream.h>
|
||||||
|
#include <Cytoplasm/Str.h>
|
||||||
|
#include <Cytoplasm/Io.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct ReaderCookie {
|
||||||
|
size_t length;
|
||||||
|
size_t offset;
|
||||||
|
char *buffer;
|
||||||
|
} ReaderCookie;
|
||||||
|
|
||||||
|
#define Remaining() (cook->length - cook->offset)
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
ReadStreamReader(void *coop, void *to, size_t n)
|
||||||
|
{
|
||||||
|
ReaderCookie *cook = coop;
|
||||||
|
size_t remaining;
|
||||||
|
if (!cook)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining = Remaining();
|
||||||
|
if (n > remaining)
|
||||||
|
{
|
||||||
|
memcpy(to, cook->buffer + cook->offset, remaining);
|
||||||
|
cook->offset = cook->length;
|
||||||
|
return remaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(to, cook->buffer + cook->offset, n);
|
||||||
|
cook->offset += n;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
static ssize_t
|
||||||
|
WriteStreamReader(void *coop, void *from, size_t n)
|
||||||
|
{
|
||||||
|
/* Writing to a stream reader is silly. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static off_t
|
||||||
|
SeekStreamReader(void *coop, off_t mag, int sgn)
|
||||||
|
{
|
||||||
|
ReaderCookie *cook = coop;
|
||||||
|
if (!cook)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (sgn)
|
||||||
|
{
|
||||||
|
case SEEK_SET:
|
||||||
|
if (mag > cook->length)
|
||||||
|
{
|
||||||
|
cook->offset = cook->length;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (mag < 0)
|
||||||
|
{
|
||||||
|
cook->offset = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cook->offset = mag;
|
||||||
|
return 0;
|
||||||
|
case SEEK_CUR:
|
||||||
|
cook->offset += mag;
|
||||||
|
if (cook->offset > cook->length)
|
||||||
|
{
|
||||||
|
cook->offset = cook->length;
|
||||||
|
}
|
||||||
|
else if (cook->offset < 0)
|
||||||
|
{
|
||||||
|
cook->offset = 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case SEEK_END:
|
||||||
|
cook->offset += cook->length + mag;
|
||||||
|
if (cook->offset > cook->length)
|
||||||
|
{
|
||||||
|
cook->offset = cook->length;
|
||||||
|
}
|
||||||
|
else if (cook->offset < 0)
|
||||||
|
{
|
||||||
|
cook->offset = 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
CloseStreamReader(void *coop)
|
||||||
|
{
|
||||||
|
/* Nothing to free as of now. */
|
||||||
|
if (coop)
|
||||||
|
{
|
||||||
|
Free(coop);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const static IoFunctions Functions = {
|
||||||
|
.read = ReadStreamReader,
|
||||||
|
.seek = SeekStreamReader,
|
||||||
|
.write = WriteStreamReader,
|
||||||
|
.close = CloseStreamReader,
|
||||||
|
};
|
||||||
|
|
||||||
|
Stream *
|
||||||
|
StrStreamReader(char *buffer)
|
||||||
|
{
|
||||||
|
Io *raw_io;
|
||||||
|
ReaderCookie *cookie;
|
||||||
|
if (!buffer)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cookie = Malloc(sizeof(*cookie));
|
||||||
|
cookie->buffer = buffer;
|
||||||
|
cookie->length = strlen(buffer);
|
||||||
|
cookie->offset = 0;
|
||||||
|
raw_io = IoCreate(cookie, Functions);
|
||||||
|
return StreamIo(raw_io);
|
||||||
|
}
|
||||||
64
src/Streams/Writer.c
Normal file
64
src/Streams/Writer.c
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
#include <StringStream.h>
|
||||||
|
|
||||||
|
#include <Cytoplasm/Memory.h>
|
||||||
|
#include <Cytoplasm/Stream.h>
|
||||||
|
#include <Cytoplasm/Str.h>
|
||||||
|
#include <Cytoplasm/Io.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
ReadStreamWriter(void *coop, void *to, size_t n)
|
||||||
|
{
|
||||||
|
/* Reading from a stream writer is silly. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static ssize_t
|
||||||
|
WriteStreamWriter(void *coop, void *from, size_t n)
|
||||||
|
{
|
||||||
|
char **cook = coop;
|
||||||
|
char *tmp = NULL;
|
||||||
|
char *str = Malloc(n + 1);
|
||||||
|
|
||||||
|
memcpy(str, from, n);
|
||||||
|
str[n] = '\0';
|
||||||
|
|
||||||
|
tmp = *cook;
|
||||||
|
*cook = StrConcat(2, *cook, str);
|
||||||
|
Free(tmp);
|
||||||
|
Free(str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static off_t
|
||||||
|
SeekStreamWriter(void *coop, off_t mag, int sgn)
|
||||||
|
{
|
||||||
|
/* TODO: Seeking would be useful, though not supported yet. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
CloseStreamWriter(void *coop)
|
||||||
|
{
|
||||||
|
/* Nothing to free as of now. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const static IoFunctions Functions = {
|
||||||
|
.read = ReadStreamWriter,
|
||||||
|
.seek = SeekStreamWriter,
|
||||||
|
.write = WriteStreamWriter,
|
||||||
|
.close = CloseStreamWriter,
|
||||||
|
};
|
||||||
|
|
||||||
|
Stream *
|
||||||
|
StrStreamWriter(char **buffer)
|
||||||
|
{
|
||||||
|
Io *raw_io;
|
||||||
|
if (!buffer)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_io = IoCreate(buffer, Functions);
|
||||||
|
return StreamIo(raw_io);
|
||||||
|
}
|
||||||
|
|
@ -99,7 +99,7 @@ XMLDecode(Stream *stream, bool autofree)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
XMLFreeElement(e);
|
//XMLFreeElement(e);
|
||||||
}
|
}
|
||||||
ArrayFree(stack);
|
ArrayFree(stack);
|
||||||
XMLFreeLexer(lexer);
|
XMLFreeLexer(lexer);
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,7 @@ XMLCrank(XMLexer *lexer)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
event = XMLCreateRelax(lexer);
|
event = XMLCreateRelax(lexer);
|
||||||
|
//Log(LOG_INFO, "A %d", lexer->state);
|
||||||
|
|
||||||
switch (lexer->state)
|
switch (lexer->state)
|
||||||
{
|
{
|
||||||
|
|
@ -213,13 +214,16 @@ XMLCrank(XMLexer *lexer)
|
||||||
break;
|
break;
|
||||||
case XML_STATE_ATTR:
|
case XML_STATE_ATTR:
|
||||||
attrname = XMLParseName(lexer);
|
attrname = XMLParseName(lexer);
|
||||||
|
//Log(LOG_INFO, "A %d %s", lexer->state, attrname);
|
||||||
if (!attrname)
|
if (!attrname)
|
||||||
{
|
{
|
||||||
/* TODO: Throw error */
|
/* TODO: Throw error */
|
||||||
}
|
}
|
||||||
XMLPushElement(lexer, attrname);
|
XMLPushElement(lexer, attrname);
|
||||||
|
|
||||||
|
//Log(LOG_INFO, "Reading props...");
|
||||||
props = XMLReadProps(lexer);
|
props = XMLReadProps(lexer);
|
||||||
|
//Log(LOG_INFO, "Read props!");
|
||||||
|
|
||||||
XMLSkipSpace(lexer);
|
XMLSkipSpace(lexer);
|
||||||
if (XMLookahead(lexer, "/>", true))
|
if (XMLookahead(lexer, "/>", true))
|
||||||
|
|
@ -516,6 +520,7 @@ XMLReadProps(XMLexer *lexer)
|
||||||
/* A lack of name is totally excepted */
|
/* A lack of name is totally excepted */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
//Log(LOG_INFO, "K=%s...", name);
|
||||||
|
|
||||||
value = StrDuplicate("");
|
value = StrDuplicate("");
|
||||||
if (XMLookahead(lexer, "=", true))
|
if (XMLookahead(lexer, "=", true))
|
||||||
|
|
@ -719,18 +724,23 @@ XMLParseAttQuote(XMLexer *lexer)
|
||||||
|
|
||||||
while ((c = XMLGetc(lexer)))
|
while ((c = XMLGetc(lexer)))
|
||||||
{
|
{
|
||||||
|
//Log(LOG_INFO, "E1=%c", c);
|
||||||
if (c == '&')
|
if (c == '&')
|
||||||
{
|
{
|
||||||
char *code = NULL;
|
char *code = NULL;
|
||||||
int c2;
|
int c2;
|
||||||
int p2 = XMLInitialiseBuffer(lexer);
|
int p2 = XMLInitialiseBuffer(lexer);
|
||||||
while ((c2 = XMLGetc(lexer)))
|
while ((c2 = XMLGetc(lexer)) && c2 != EOF)
|
||||||
{
|
{
|
||||||
if (c2 == ';')
|
if (c2 == ';')
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (c2 != ';')
|
||||||
|
{
|
||||||
|
XMLReset(lexer, p2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!IsNormalQ(c))
|
else if (!IsNormalQ(c))
|
||||||
{
|
{
|
||||||
|
|
@ -759,18 +769,23 @@ XMLParseAttDouble(XMLexer *lexer)
|
||||||
|
|
||||||
while ((c = XMLGetc(lexer)))
|
while ((c = XMLGetc(lexer)))
|
||||||
{
|
{
|
||||||
|
//Log(LOG_INFO, "E2=%c", c);
|
||||||
if (c == '&')
|
if (c == '&')
|
||||||
{
|
{
|
||||||
char *code = NULL;
|
char *code = NULL;
|
||||||
int c2;
|
int c2;
|
||||||
int p2 = XMLInitialiseBuffer(lexer);
|
int p2 = XMLInitialiseBuffer(lexer);
|
||||||
while ((c2 = XMLGetc(lexer)))
|
while ((c2 = XMLGetc(lexer)) && c2 != EOF)
|
||||||
{
|
{
|
||||||
if (c2 == ';')
|
if (c2 == ';')
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (c2 != ';')
|
||||||
|
{
|
||||||
|
XMLReset(lexer, p2);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (!IsNormalD(c))
|
else if (!IsNormalD(c))
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,83 @@ MessageStanza(ParseeData *args, XMLElement *stanza)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DISCO "http://jabber.org/protocol/disco#info"
|
||||||
|
static void
|
||||||
|
IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza)
|
||||||
|
{
|
||||||
|
char *from, *to, *id;
|
||||||
|
XMLElement *iq_reply, *query;
|
||||||
|
|
||||||
|
from = HashMapGet(stanza->attrs, "from");
|
||||||
|
to = HashMapGet(stanza->attrs, "to");
|
||||||
|
id = HashMapGet(stanza->attrs, "id");
|
||||||
|
|
||||||
|
/* Generate an IQ reply with discovery information */
|
||||||
|
iq_reply = XMLCreateTag("iq");
|
||||||
|
XMLAddAttr(iq_reply, "to", from);
|
||||||
|
XMLAddAttr(iq_reply, "from", to);
|
||||||
|
XMLAddAttr(iq_reply, "type", "result");
|
||||||
|
XMLAddAttr(iq_reply, "id", id);
|
||||||
|
{
|
||||||
|
query = XMLCreateTag("query");
|
||||||
|
XMLAddAttr(query, "xmlns", DISCO);
|
||||||
|
{
|
||||||
|
XMLElement *feature;
|
||||||
|
#define AdvertiseSimple(f) do \
|
||||||
|
{ \
|
||||||
|
feature = XMLCreateTag("feature"); \
|
||||||
|
XMLAddAttr(feature, "var", f); \
|
||||||
|
XMLAddChild(query, feature); \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
|
||||||
|
AdvertiseSimple("urn:xmpp:reply:0");
|
||||||
|
AdvertiseSimple("urn:xmpp:styling:0");
|
||||||
|
|
||||||
|
AdvertiseSimple("urn:parsee:x-parsee:0");
|
||||||
|
AdvertiseSimple("urn:parsee:jealousy:0");
|
||||||
|
/* TODO: Advertise more things */
|
||||||
|
#undef AdvertiseSimple
|
||||||
|
}
|
||||||
|
XMLAddChild(iq_reply, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&jabber->write_lock);
|
||||||
|
XMLEncode(jabber->stream, iq_reply);
|
||||||
|
pthread_mutex_unlock(&jabber->write_lock);
|
||||||
|
|
||||||
|
XMLFreeElement(iq_reply);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
IQGet(ParseeData *args, XMLElement *stanza)
|
||||||
|
{
|
||||||
|
XMPPComponent *jabber = args->jabber;
|
||||||
|
if (XMLookForTKV(stanza, "query", "xmlns", DISCO))
|
||||||
|
{
|
||||||
|
IQDiscoGet(args, jabber, stanza);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#undef DISCO
|
||||||
|
static void
|
||||||
|
IQStanza(ParseeData *args, XMLElement *stanza)
|
||||||
|
{
|
||||||
|
char *type;
|
||||||
|
type = HashMapGet(stanza->attrs, "type");
|
||||||
|
#define OnType(ctyp, callback) do \
|
||||||
|
{ \
|
||||||
|
if (StrEquals(type, #ctyp)) \
|
||||||
|
{ \
|
||||||
|
callback(args, stanza); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
|
||||||
|
OnType(get, IQGet);
|
||||||
|
#undef OnType
|
||||||
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
ParseeXMPPThread(void *argp)
|
ParseeXMPPThread(void *argp)
|
||||||
{
|
{
|
||||||
|
|
@ -177,10 +254,7 @@ ParseeXMPPThread(void *argp)
|
||||||
}
|
}
|
||||||
else if (StrEquals(stanza->name, "iq"))
|
else if (StrEquals(stanza->name, "iq"))
|
||||||
{
|
{
|
||||||
/* TODO: Ought to manage info/query requests */
|
IQStanza(args, stanza);
|
||||||
Log(LOG_WARNING, "Unimplemented 'iq' stanza.");
|
|
||||||
Log(LOG_WARNING, "Odds are, this is the programmer's fault");
|
|
||||||
Log(LOG_WARNING, "and this needs to be implemented later on.");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -163,4 +163,8 @@ extern void ParseeCleanup(void *data);
|
||||||
|
|
||||||
/* Finds the offset of the first line without a '>' at its start. */
|
/* Finds the offset of the first line without a '>' at its start. */
|
||||||
extern int ParseeFindDatastart(char *data);
|
extern int ParseeFindDatastart(char *data);
|
||||||
|
|
||||||
|
|
||||||
|
/* XMPP-ifies a message event to XEP-0393 if possible. */
|
||||||
|
extern char * ParseeXMPPify(HashMap *event);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
13
src/include/StringStream.h
Normal file
13
src/include/StringStream.h
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef PARSEE_STRSTREAM_H
|
||||||
|
#define PARSEE_STRSTREAM_H
|
||||||
|
|
||||||
|
#include <Cytoplasm/Stream.h>
|
||||||
|
|
||||||
|
/* Creates a string stream writer. The referenced buffer must be in the heap,
|
||||||
|
* or NULL. */
|
||||||
|
extern Stream * StrStreamWriter(char **buffer);
|
||||||
|
|
||||||
|
/* Creates a string stream reader. The referenced buffer may be everywhere. */
|
||||||
|
extern Stream * StrStreamReader(char *buffer);
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Add table
Add a link
Reference in a new issue