#include #include #include #include #include #include #include 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->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 = ParseeFindDatastart(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_stanza); XMLAddAttr(reply, "id", builder->replying_to_sender); 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) { XMLElement *elem; if (!builder || !jabber) { return; } elem = ExportStanza(builder); pthread_mutex_lock(&jabber->write_lock); XMLEncode(jabber->stream, elem); StreamFlush(jabber->stream); pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(elem); return; } 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_text, *text_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); parsee_text = XMLCreateTag("zayds-note"); text_elem = XMLCreateText("\"LDA HANG YOURSELF\" - Zayd"); XMLAddChild(parsee_text, text_elem); XMLAddChild(parsee, parsee_text); parsee_text = XMLCreateTag("mcnebs-note"); text_elem = XMLCreateText("LDA will never beat the allegations"); XMLAddChild(parsee_text, text_elem); XMLAddChild(parsee, parsee_text); 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); }