#include #include #include #include #include #include void XMPPSendPlain(XMPPComponent *comp, char *fr, char *to, char *msg, char *type, char *rst, char *rse, char *event_id, char *oob, char *edit) { char *ident = StrRandom(32); XMPPSendPlainID(comp, fr, to, msg, type, rst, rse, event_id, oob, edit, ident); Free(ident); } void XMPPRetract(XMPPComponent *comp, char *fr, char *to, char *type, char *redact) { XMLElement *message; char *ident = StrRandom(32), *from; if (!comp || !fr || !to || !type || !redact) { Free(ident); return; } message = XMLCreateTag("message"); XMLAddAttr(message, "from", (from = StrConcat(3, fr, "@", comp->host))); XMLAddAttr(message, "to", to); XMLAddAttr(message, "type", type); XMLAddAttr(message, "id", ident); { XMLElement *apply_to, *retract, *body, *txt, *fallback; apply_to = XMLCreateTag("apply-to"); XMLAddAttr(apply_to, "xmlns", "urn:xmpp:fasten:0"); XMLAddAttr(apply_to, "id", redact); { retract = XMLCreateTag("retract"); XMLAddAttr(retract, "xmlns", "urn:xmpp:message-retract:0"); XMLAddChild(apply_to, retract); } XMLAddChild(message, apply_to); retract = XMLCreateTag("retract"); XMLAddAttr(retract, "xmlns", "urn:xmpp:message-retract:1"); XMLAddAttr(retract, "id", redact); XMLAddChild(message, retract); fallback = XMLCreateTag("fallback"); XMLAddAttr(fallback, "xmlns", "urn:xmpp:fallback:0"); XMLAddAttr(fallback, "for", "urn:xmpp:message-retract:0"); XMLAddChild(message, fallback); fallback = XMLCreateTag("fallback"); XMLAddAttr(fallback, "xmlns", "urn:xmpp:fallback:0"); XMLAddAttr(fallback, "for", "urn:xmpp:message-retract:1"); XMLAddChild(message, fallback); body = XMLCreateTag("body"); txt = XMLCreateText( "This person attempted to retract a previous message, " "but your client does not yet support the 0.4.1 version of " "XEP-0424.\n\n" "(_Parsee is jealous of being able to read such messages._)" ); XMLAddChild(body, txt); XMLAddChild(message, body); } pthread_mutex_lock(&comp->write_lock); XMLEncode(comp->stream, message); StreamFlush(comp->stream); XMLFreeElement(message); pthread_mutex_unlock(&comp->write_lock); Free(from); Free(ident); } void XMPPSendPlainID(XMPPComponent *comp, char *fr, char *to, char *msg, char *type, char *rst, char *rse, char *event_id, char *oob, char *edit, char *ident) { XMLElement *message, *body, *data, *parsee; char *from; if (!comp || !fr || !to || !msg || !ident) { return; } pthread_mutex_lock(&comp->write_lock); message = XMLCreateTag("message"); XMLAddAttr(message, "from", (from = StrConcat(3, fr, "@", comp->host))); XMLAddAttr(message, "to", to); XMLAddAttr(message, "type", type); XMLAddAttr(message, "id", ident); body = XMLCreateTag("body"); data = XMLCreateText(oob ? oob : msg); /* TODO: Add Parsee specific fields here */ parsee = XMLCreateTag("x-parsee"); { XMLElement *parsee_version, *ver_elem; XMLElement *parsee_link, *link_elem; XMLElement *parsee_text, *text_elem; XMLElement *parsee_event, *event_elem; parsee_version = XMLCreateTag("version"); ver_elem = XMLCreateText(VERSION); XMLAddChild(parsee_version, ver_elem); XMLAddChild(parsee, parsee_version); 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); } /* TODO: Add custom fields depending on the caller's wishes */ } if (edit) { XMLElement *xedit = XMLCreateTag("replace"); XMLAddAttr(xedit, "xmlns", "urn:xmpp:message-correct:0"); XMLAddAttr(xedit, "id", edit); XMLAddChild(message, xedit); } { XMLElement *request = XMLCreateTag("request"); XMLAddAttr(request, "xmlns", "urn:xmpp:receipts"); XMLAddChild(message, request); } { XMLElement *markable = XMLCreateTag("markable"); XMLAddAttr(markable, "xmlns", "urn:xmpp:chat-markers:0"); XMLAddChild(message, markable); } if (oob) { XMLElement *xoob, *oob_data, *oob_url; xoob = XMLCreateTag("x"); XMLAddAttr(xoob, "xmlns", "jabber:x:oob"); oob_url = XMLCreateTag("url"); oob_data = XMLCreateText(oob); XMLAddChild(oob_url, oob_data); XMLAddChild(xoob, oob_url); XMLAddChild(message, xoob); } if (rst && rse) { int off = ParseeFindDatastart(msg); char *ostr = StrInt(off); XMLElement *reply = XMLCreateTag("reply"); XMLElement *fallback = XMLCreateTag("fallback"); XMLElement *fall_body = XMLCreateTag("body"); XMLAddAttr(reply, "to", rse); XMLAddAttr(reply, "id", rst); 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(message, reply); XMLAddChild(message, fallback); Free(ostr); } XMLAddChild(message, body); XMLAddChild(message, parsee); XMLAddChild(body, data); XMLEncode(comp->stream, message); StreamFlush(comp->stream); XMLFreeElement(message); Free(from); pthread_mutex_unlock(&comp->write_lock); } void XMPPSendMUC(XMPPComponent *comp, char *fr, char *as, char *to, char *msg, char *type) { XMLElement *message, *body, *data; char *from, *id; if (!comp || !fr || !to || !as || !msg) { return; } pthread_mutex_lock(&comp->write_lock); message = XMLCreateTag("message"); XMLAddAttr(message, "from", (from = StrConcat(5, fr, "@", comp->host, "/", as))); XMLAddAttr(message, "to", to); XMLAddAttr(message, "type", type); XMLAddAttr(message, "id", (id = StrRandom(8))); body = XMLCreateTag("body"); data = XMLCreateText(msg); XMLAddChild(message, body); XMLAddChild(body, data); XMLEncode(comp->stream, message); StreamFlush(comp->stream); XMLFreeElement(message); Free(from); Free(id); pthread_mutex_unlock(&comp->write_lock); } void XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) { XMLElement *presence; char *from, *id; if (!comp || !fr || !muc) { return; } pthread_mutex_lock(&comp->write_lock); presence = XMLCreateTag("presence"); XMLAddAttr(presence, "from", (from = StrConcat(3, fr, "@", comp->host))); XMLAddAttr(presence, "to", muc); XMLAddAttr(presence, "id", (id = StrRandom(8))); XMLAddAttr(presence, "type", "unavailable"); if (reason) { XMLElement *status = XMLCreateTag("status"); XMLElement *string = XMLCreateText(reason); XMLAddChild(status, string); XMLAddChild(presence, status); } XMPPAnnotatePresence(presence); XMLEncode(comp->stream, presence); StreamFlush(comp->stream); XMLFreeElement(presence); Free(from); Free(id); pthread_mutex_unlock(&comp->write_lock); } bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc) { XMLElement *presence, *x, *reply; char *from, *id; if (!comp || !fr || !muc) { return false; } pthread_mutex_lock(&comp->write_lock); presence = XMLCreateTag("presence"); x = XMLCreateTag("x"); XMLAddAttr(presence, "from", (from = StrConcat(3, fr, "@", comp->host))); XMLAddAttr(presence, "to", muc); XMLAddAttr(presence, "id", (id = StrRandom(8))); XMLAddAttr(x, "xmlns", "http://jabber.org/protocol/muc"); XMLAddChild(presence, x); XMPPAnnotatePresence(presence); XMLEncode(comp->stream, presence); StreamFlush(comp->stream); XMLFreeElement(presence); Free(from); pthread_mutex_unlock(&comp->write_lock); /*if ((reply = ParseeAwaitStanza(id, 500))) { bool exit_code = true; if (XMPPHasError(reply, "conflict")) { Log(LOG_WARNING, "UNIMPLEMENTED NAMING CONFLICT."); exit_code = false; } XMLFreeElement(reply); Free(id); return exit_code; }*/ (void) reply; Free(id); return true; } bool XMPPIsParseeStanza(XMLElement *stanza) { if (!stanza) { return false; } return !!XMLookForUnique(stanza, "x-parsee"); } char * XMPPGetStanzaID(XMLElement *stanza) { XMLElement *stanza_id; if (!stanza) { return NULL; } stanza_id = XMLookForTKV(stanza, "stanza-id", "xmlns", "urn:xmpp:sid:0"); return stanza_id ? HashMapGet(stanza_id->attrs, "id") : NULL; } char * XMPPGetOriginID(XMLElement *stanza) { XMLElement *origin_id; if (!stanza) { return NULL; } origin_id = XMLookForTKV(stanza, "origin-id", "xmlns", "urn:xmpp:sid:0"); return origin_id ? HashMapGet(origin_id->attrs, "id") : NULL; } char * XMPPGetReplacedID(XMLElement *stanza) { XMLElement *replace = XMLookForTKV( stanza, "replace", "xmlns", "urn:xmpp:message-correct:0" ); return replace ? HashMapGet(replace->attrs, "id") : NULL; } char * XMPPGetRetractedID(XMLElement *stanza) { XMLElement *retract = XMLookForTKV( stanza, "retract", "xmlns", "urn:xmpp:message-retract:1" ); char *id = retract ? HashMapGet(retract->attrs, "id") : NULL; if (!id) { /* Pretend its fastened */ XMLElement *fasten = XMLookForTKV( stanza, "apply-to", "xmlns", "urn:xmpp:fasten:0" ); retract = XMLookForTKV( fasten, "retract", "xmlns", "urn:xmpp:message-retract:0" ); if (retract) { id = HashMapGet(fasten->attrs, "id"); } } return id; } char * XMPPGetReply(XMLElement *elem) { XMLElement *rep = XMLookForTKV(elem, "reply", "xmlns", "urn:xmpp:reply:0"); if (!rep) { return NULL; } return HashMapGet(rep->attrs, "id"); } void XMPPAnnotatePresence(XMLElement *presence) { XMLElement *c; char *ver; if (!presence) { return; } ver = XMPPGenerateVer(); c = XMLCreateTag("c"); XMLAddAttr(c, "xmlns", "http://jabber.org/protocol/caps"); XMLAddAttr(c, "hash", "sha-1"); XMLAddAttr(c, "node", REPOSITORY); XMLAddAttr(c, "ver", ver); Free(ver); XMLAddChild(presence, c); } char * XMPPGetModeration(XMLElement *stanza) { #define MOD_BASE "urn:xmpp:message-moderate" XMLElement *moderate; XMLElement *fasten; if (!stanza) { return NULL; } /* 0.3.0 version of XEP-0425: Bare look at the moderate element */ moderate = XMLookForTKV(stanza, "moderate", "xmlns", MOD_BASE ":1"); if (moderate) { return HashMapGet(moderate->attrs, "id"); } /* Earlier versions, which still depend on fastening. */ fasten = XMLookForTKV( stanza, "apply-to", "xmlns", "urn:xmpp:fasten:0" ); moderate = XMLookForTKV( fasten, "moderated", "xmlns", MOD_BASE ":0" ); if (moderate) { return HashMapGet(fasten->attrs, "id"); } return NULL; #undef MOD_BASE } bool XMPPHasError(XMLElement *stanza, char *type) { XMLElement *err; if (!stanza || !type) { return false; } err = XMLookForUnique(stanza, "error"); if (!err) { return false; } return XMLookForUnique(err, type); } XMLElement * XMPPSendDisco(XMPPComponent *jabber, char *from, char *to) { XMLElement *ret, *iq; char *identifier; if (!jabber || !from || !to) { return NULL; } iq = XMLCreateTag("iq"); XMLAddAttr(iq, "type", "get"); XMLAddAttr(iq, "from", from); XMLAddAttr(iq, "to", to); XMLAddAttr(iq, "id", (identifier = StrRandom(69))); { XMLElement *query = XMLCreateTag("query"); XMLAddAttr(query, "xmlns", "http://jabber.org/protocol/disco#info"); XMLAddChild(iq, query); } pthread_mutex_lock(&jabber->write_lock); XMLEncode(jabber->stream, iq); StreamFlush(jabber->stream); pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(iq); ret = ParseeAwaitStanza(identifier, 250); Free(identifier); return ret; } bool XMPPDiscoAdvertises(XMLElement *disco, char *var) { XMLElement *query; if (!disco || !var) { return false; } query = XMLookForTKV( disco, "query", "xmlns", "http://jabber.org/protocol/disco#info" ); if (!query) { return false; } return !!XMLookForTKV(query, "feature", "var", var); }