Parsee/src/StanzaBuilder.c
2024-10-25 18:03:05 +02:00

326 lines
7.6 KiB
C

#include <StanzaBuilder.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Array.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Str.h>
#include <StringStream.h>
#include <Parsee.h>
struct StanzaBuilder {
Array *sub_items;
char *replying_to_stanza;
char *replying_to_sender;
char *from, *to;
char *editing;
char *type;
char *body;
char *oob;
char *id;
};
StanzaBuilder *
CreateStanzaBuilder(char *from, char *to, char *id)
{
StanzaBuilder *builder;
if (!from || !to)
{
return NULL;
}
builder = Malloc(sizeof(*builder));
builder->sub_items = ArrayCreate();
builder->id = id ? StrRandom(64) : StrDuplicate(id);
builder->from = StrDuplicate(from);
builder->to = StrDuplicate(to);
builder->replying_to_stanza = NULL;
builder->replying_to_sender = NULL;
builder->editing = NULL;
builder->type = NULL;
builder->body = NULL;
builder->oob = NULL;
return SetStanzaType(builder, "chat");
}
StanzaBuilder *
SetStanzaType(StanzaBuilder *builder, char *type)
{
if (!builder || !type)
{
return builder;
}
Free(builder->type);
builder->type = StrDuplicate(type);
return builder;
}
StanzaBuilder *
SetStanzaReply(StanzaBuilder *builder, char *stanza, char *sender)
{
if (!builder || !stanza || !sender)
{
return builder;
}
Free(builder->replying_to_stanza);
Free(builder->replying_to_sender);
builder->replying_to_stanza = StrDuplicate(stanza);
builder->replying_to_sender = StrDuplicate(sender);
return builder;
}
StanzaBuilder *
SetStanzaEdit(StanzaBuilder *builder, char *to)
{
if (!builder || !to)
{
return builder;
}
Free(builder->editing);
builder->editing = StrDuplicate(to);
return builder;
}
StanzaBuilder *
SetStanzaBody(StanzaBuilder *builder, char *body)
{
if (!builder || !body)
{
return builder;
}
Free(builder->body);
builder->body = StrDuplicate(body);
return builder;
}
StanzaBuilder *
SetStanzaID(StanzaBuilder *builder, char *id)
{
if (!builder || !id)
{
return builder;
}
Free(builder->id);
builder->id = StrDuplicate(id);
return builder;
}
StanzaBuilder *
SetStanzaLink(StanzaBuilder *builder, char *oob)
{
if (!builder || !oob)
{
return builder;
}
Free(builder->oob);
builder->oob = StrDuplicate(oob);
return builder;
}
StanzaBuilder *
AddStanzaElem(StanzaBuilder *builder, XMLElement *item)
{
if (!builder || !item)
{
return builder;
}
ArrayAdd(builder->sub_items, item);
return builder;
}
XMLElement *
ExportStanza(StanzaBuilder *builder)
{
XMLElement *elem, *request, *markable;
size_t i;
if (!builder)
{
return NULL;
}
elem = XMLCreateTag("message");
XMLAddAttr(elem, "from", builder->from);
XMLAddAttr(elem, "to", builder->to);
XMLAddAttr(elem, "id", builder->id);
XMLAddAttr(elem, "type", builder->type);
request = XMLCreateTag("request");
XMLAddAttr(request, "xmlns", "urn:xmpp:receipts");
XMLAddChild(elem, request);
markable = XMLCreateTag("markable");
XMLAddAttr(markable, "xmlns", "urn:xmpp:chat-markers:0");
XMLAddChild(elem, markable);
if (builder->editing)
{
XMLElement *xedit = XMLCreateTag("replace");
XMLAddAttr(xedit, "xmlns", "urn:xmpp:message-correct:0");
XMLAddAttr(xedit, "id", builder->editing);
XMLAddChild(elem, xedit);
}
if (builder->oob)
{
XMLElement *xoob, *oob_data, *oob_url;
xoob = XMLCreateTag("x");
oob_url = XMLCreateTag("url");
oob_data = XMLCreateText(builder->oob);
XMLAddAttr(xoob, "xmlns", "jabber:x:oob");
XMLAddChild(elem, xoob);
XMLAddChild(xoob, oob_url);
XMLAddChild(oob_url, oob_data);
}
if (builder->replying_to_stanza &&
builder->replying_to_sender &&
builder->body)
{
int off = ParseeFindDatastartU(builder->body);
char *ostr = StrInt(off);
XMLElement *reply = XMLCreateTag("reply");
XMLElement *fallback = XMLCreateTag("fallback");
XMLElement *fall_body = XMLCreateTag("body");
XMLAddAttr(reply, "to", builder->replying_to_sender);
XMLAddAttr(reply, "id", builder->replying_to_stanza);
XMLAddAttr(reply, "xmlns", "urn:xmpp:reply:0");
XMLAddAttr(fallback, "xmlns", "urn:xmpp:fallback:0");
XMLAddAttr(fallback, "for", "urn:xmpp:reply:0");
XMLAddAttr(fall_body, "start", "0");
XMLAddAttr(fall_body, "end", ostr);
XMLAddChild(fallback, fall_body);
XMLAddChild(elem, reply);
XMLAddChild(elem, fallback);
Free(ostr);
}
if (builder->body)
{
XMLElement *body = XMLCreateTag("body");
XMLElement *text = XMLCreateText(builder->body);
XMLAddChild(elem, body);
XMLAddChild(body, text);
}
for (i = 0; i < ArraySize(builder->sub_items); i++)
{
XMLElement *sub_item = ArrayGet(builder->sub_items, i);
XMLElement *dup = XMLCopy(sub_item);
XMLAddChild(elem, dup);
}
return elem;
}
void
WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber, size_t max)
{
XMLElement *elem;
if (!builder || !jabber)
{
return;
}
if (!max)
{
max = 10000; /* XMPP recommended limit */
}
elem = ExportStanza(builder);
XMPPSendStanza(jabber, elem, max);
XMLFreeElement(elem);
}
StanzaBuilder *
SetStanzaXParsee(StanzaBuilder *builder, HashMap *e)
{
XMLElement *parsee;
if (!builder || !e)
{
return builder;
}
parsee = XMLCreateTag("x-parsee");
XMLAddAttr(parsee, "xmlns", "https://at.kappach.at/jabber/parsee#info");
{
XMLElement *parsee_version, *ver_elem;
XMLElement *parsee_link, *link_elem;
XMLElement *parsee_event, *event_elem;
XMLElement *parsee_json, *json_elem;
char *event_id = GrabString(e, 1, "event_id");
char *json = NULL;
Stream *stream = StrStreamWriter(&json);
JsonEncode(e, stream, JSON_DEFAULT);
StreamFlush(stream);
StreamClose(stream);
parsee_version = XMLCreateTag("version");
ver_elem = XMLCreateText(VERSION "[" CODE "]");
XMLAddChild(parsee_version, ver_elem);
XMLAddChild(parsee, parsee_version);
parsee_json = XMLCreateTag("json");
json_elem = XMLCreateText(json);
XMLAddChild(parsee_json, json_elem);
XMLAddChild(parsee, parsee_json);
Free(json);
parsee_link = XMLCreateTag("repository");
link_elem = XMLCreateText(REPOSITORY);
XMLAddChild(parsee_link, link_elem);
XMLAddChild(parsee, parsee_link);
if (event_id)
{
parsee_event = XMLCreateTag("event-id");
event_elem = XMLCreateText(event_id);
XMLAddChild(parsee_event, event_elem);
XMLAddChild(parsee, parsee_event);
}
}
AddStanzaElem(builder, parsee);
return builder;
}
void
DestroyStanzaBuilder(StanzaBuilder *builder)
{
size_t i;
if (!builder)
{
return;
}
for (i = 0; i < ArraySize(builder->sub_items); i++)
{
XMLElement *sub_item = ArrayGet(builder->sub_items, i);
XMLFreeElement(sub_item);
}
ArrayFree(builder->sub_items);
Free(builder->replying_to_stanza);
Free(builder->replying_to_sender);
Free(builder->editing);
Free(builder->from);
Free(builder->body);
Free(builder->type);
Free(builder->oob);
Free(builder->to);
Free(builder->id);
Free(builder);
}