diff --git a/src/Commands/SetPL.c b/src/Commands/SetPL.c index 493ee44..ef2fdb6 100644 --- a/src/Commands/SetPL.c +++ b/src/Commands/SetPL.c @@ -2,6 +2,7 @@ #include +#include #include CommandHead(CmdSetPL, cmd, argp) @@ -26,3 +27,25 @@ CommandHead(CmdSetPL, cmd, argp) )); ASSetPL(data->config, room, map); } +CommandHead(CmdSetMin, cmd, argp) +{ + ParseeCmdArg *args = argp; + ParseeData *data = args->data; + char *event = HashMapGet(cmd->arguments, "event"); + char *room = HashMapGet(cmd->arguments, "room"); + char *pl_str = HashMapGet(cmd->arguments, "pl"); + long pl = strtol(pl_str, NULL, 10); + HashMap *map; + + + if (!event || !pl_str) + { + return; + } + map = ASGetPL(data->config, room); + JsonValueFree(JsonSet( + map, JsonValueInteger(pl), + 2, "events", event + )); + ASSetPL(data->config, room, map); +} diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 9b8346c..c867977 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -23,7 +23,7 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) if (StrEquals(membership, "invite") && ParseeIsPuppet(conf, state_key)) { - DbRef *ref; + DbRef *ref = NULL; HashMap *json; char *jid; bool direct = GrabBoolean(event, 2, "content", "is_direct"); @@ -125,18 +125,24 @@ static void ParseeMessageHandler(ParseeData *data, HashMap *event) { XMPPComponent *jabber = data->jabber; - DbRef *ref; + DbRef *ref = NULL; HashMap *json; char *msgtype = GrabString(event, 2, "content", "msgtype"); char *body = GrabString(event, 2, "content", "body"); char *id = GrabString(event, 1, "room_id"); char *ev_id = GrabString(event, 1, "event_id"); - char *sender = GrabString(event, 1, "sender"); + char *m_sender = GrabString(event, 1, "sender"); char *chat_id, *muc_id, *jid; char *reply_id = MatrixGetReply(event); char *xepd = ParseeXMPPify(event); char *cmd_lp = data->config->sender_localpart; + char *type, *user, *xmppified_user = NULL, *to; + char *unauth = NULL; + char *origin_id = NULL, *stanza = NULL; + char *sender = NULL; + char *unedited_id = MatrixGetEdit(event); + char *url = GrabString(event, 2, "content", "url"); bool direct = false; @@ -146,13 +152,14 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) json = DbJson(ref); direct = JsonValueAsBoolean(HashMapGet(json, "is_direct")); - if (ParseeIsPuppet(data->config, sender) || - ParseeManageBan(data, sender, id)) + if (ParseeIsPuppet(data->config, m_sender) || + ParseeManageBan(data, m_sender, id)) { DbUnlock(data->db, ref); Free(chat_id); Free(reply_id); Free(xepd); + Free(unedited_id); return; } @@ -164,74 +171,99 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) Free(chat_id); Free(reply_id); Free(xepd); + Free(unedited_id); return; } + /* TODO: Reunite DM/MUC code to bring feature parity. */ + type = direct ? "chat" : "groupchat"; + user = GrabString(json, 1, "xmpp_user"); + unauth = ParseeToUnauth(data, url); if (direct) { - char *user = GrabString(json, 1, "xmpp_user"); - char *local = ParseeEncodeMXID(sender); + xmppified_user = ParseeEncodeMXID(m_sender); + to = StrDuplicate(user); - Log(LOG_INFO," Sending to %s as %s", user, local); - - XMPPSendPlain(jabber, local, user, body, "chat", NULL, NULL, ev_id, NULL, NULL); - - DbUnlock(data->db, ref); Free(chat_id); - Free(local); - Free(reply_id); - Free(xepd); - return; } + else + { + char *name, *rev, *stanza; + /* Try to find the chat ID */ + muc_id = ParseeGetMUCID(data, chat_id); + if (!chat_id) + { + goto end; + } + xmppified_user = ParseeEncodeMXID(m_sender); - DbUnlock(data->db, ref); - /* Try to find the chat ID */ - muc_id = ParseeGetMUCID(data, chat_id); - if (!chat_id) - { - Free(reply_id); - Free(xepd); - return; - } - jid = ParseeEncodeMXID(sender); - { /* TODO: Check the name's validity */ - char *name = ASGetName(data->config, id, sender); - char *rev = StrConcat(4, muc_id, "/", name, "[p]"); - char *stanza = NULL, *sender = NULL; - char *url = GrabString(event, 2, "content", "url"); - char *unauth = ParseeToUnauth(data, url); + name = ASGetName(data->config, id, m_sender); + rev = StrConcat(4, muc_id, "/", name, "[p]"); + + XMPPJoinMUC(jabber, xmppified_user, rev); + + to = muc_id; - char *unedited_id = MatrixGetEdit(event); - char *origin_id = NULL; - if (reply_id) - { - ParseeGetStanzaInfo(data, chat_id, reply_id, &stanza, &sender); - } - else if (unedited_id) - { - ParseeGetOrigin(data, chat_id, unedited_id, &origin_id); - } - XMPPJoinMUC(jabber, jid, rev); - XMPPSendPlain( - jabber, jid, muc_id, - xepd ? xepd : body, "groupchat", - stanza, sender, ev_id, unauth, origin_id - ); - Free(rev); Free(name); - Free(stanza); - Free(sender); - Free(unauth); - Free(origin_id); - Free(unedited_id); + Free(rev); } + if (reply_id) + { + /* TODO: Monocles chat DM users HATE this trick! + * Replies don't work there. Go figure why. */ + if (!ParseeGetStanzaInfo(data, chat_id, reply_id, &stanza, &sender)) + { + ParseeGetDMStanzaInfo(data, id, reply_id, &stanza, &sender); + } + } + else if (unedited_id) + { + if (!ParseeGetOrigin(data, chat_id, unedited_id, &origin_id)) + { + ParseeGetDMOrigin(data, id, unedited_id, &origin_id); + } + } + + if (direct && sender) + { + char *sndr_tmp = sender; + sender = ParseeTrimJID(sender); + Free(sndr_tmp); + } + { + char *xmpp_ident = StrRandom(32); + XMPPSendPlainID( + jabber, xmppified_user, to, + xepd ? xepd : body, type, + stanza, sender, ev_id, unauth, origin_id, + xmpp_ident + ); + /* Culprit */ + if (direct) + { + ParseePushDMStanza( + data, id, NULL, + xmpp_ident, ev_id, + xmppified_user + ); + } + Free(xmpp_ident); + } +end: + Free(origin_id); + Free(xmppified_user); Free(chat_id); - Free(muc_id); - Free(jid); + Free(to); Free(reply_id); Free(xepd); + Free(stanza); + Free(sender); + Free(unauth); + Free(unedited_id); + + DbUnlock(data->db, ref); } void diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 306f3a9..99bd4e7 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -81,8 +81,9 @@ ParseeCleanup(void *datp) ref = DbLock(data->db, 2, "chats", chat); json = DbJson(ref); -#define CleanupField(field, timeout) do \ +#define CleanupField(field, timeout, threshold) do \ { \ + size_t fields = 0, cleaned = 0; \ field##s = JsonValueAsObject(HashMapGet(json, #field"s")); \ to_delete = ArrayCreate(); \ while (HashMapIterate(field##s, &field, (void **) &val)) \ @@ -90,31 +91,90 @@ ParseeCleanup(void *datp) HashMap *obj = JsonValueAsObject(val); \ uint64_t age = JsonValueAsInteger(HashMapGet(obj, "age")); \ uint64_t dur = ts - age; \ + fields++; \ \ if ((dur > (timeout))) \ { \ ArrayAdd(to_delete, StrDuplicate(field)); \ + cleaned++; \ } \ } \ \ for (j = 0; j < ArraySize(to_delete); j++) \ { \ field = ArrayGet(to_delete, j); \ - JsonValueFree(HashMapDelete(field##s, field)); \ + if (cleaned > threshold) \ + { \ + JsonValueFree(HashMapDelete(field##s, field)); \ + } \ Free(field); \ } \ ArrayFree(to_delete); \ } \ while (0) - CleanupField(stanza, 3 HOURS); - CleanupField(event, 3 HOURS); - CleanupField(id, 3 HOURS); + CleanupField(stanza, 30 MINUTES, 50); + CleanupField(event, 30 MINUTES, 50); + CleanupField(id, 30 MINUTES, 50); DbUnlock(data->db, ref); } DbListFree(chats); /* TODO */ + chats = DbList(data->db, 1, "rooms"); + + for (i = 0; i < ArraySize(chats); i++) + { + DbRef *ref; + HashMap *json, *stanzas, *events, *ids; + char *stanza, *event, *id; + JsonValue *val; + Array *to_delete; + size_t j; + + chat = ArrayGet(chats, i); + ref = DbLock(data->db, 3, "rooms", chat, "data"); + json = DbJson(ref); + +#define CleanupField(field, timeout, threshold) do \ + { \ + size_t fields = 0, cleaned = 0; \ + field##s = JsonValueAsObject(HashMapGet(json, #field"s")); \ + to_delete = ArrayCreate(); \ + while (HashMapIterate(field##s, &field, (void **) &val)) \ + { \ + HashMap *obj = JsonValueAsObject(val); \ + uint64_t age = JsonValueAsInteger(HashMapGet(obj, "age")); \ + uint64_t dur = ts - age; \ + fields++; \ + \ + if ((dur > (timeout))) \ + { \ + ArrayAdd(to_delete, StrDuplicate(field)); \ + cleaned++; \ + } \ + } \ + \ + for (j = 0; j < ArraySize(to_delete); j++) \ + { \ + field = ArrayGet(to_delete, j); \ + if (cleaned > threshold) \ + { \ + JsonValueFree(HashMapDelete(field##s, field)); \ + } \ + Free(field); \ + } \ + ArrayFree(to_delete); \ + } \ + while (0) + + CleanupField(stanza, 3 HOURS, 50); + CleanupField(event, 3 HOURS, 50); + CleanupField(id, 3 HOURS, 50); + + DbUnlock(data->db, ref); + } + DbListFree(chats); } int ParseeFindDatastart(char *data) @@ -353,6 +413,85 @@ ParseeXMPPify(HashMap *event) return xepd; } void +ParseePushDMStanza(ParseeData *data, char *room_id, char *stanza_id, char *id, char *ev, char *sender) +{ + DbRef *ref; + HashMap *j; + HashMap *stanzas, *obj, *events, *ids; + bool new_stanzas = false, new_events = false; + bool new_ids = false; + uint64_t age = UtilTsMillis(); + if (!data || !room_id || !ev || !sender) + { + return; + } + + ref = DbLock(data->db, 3, "rooms", room_id, "data"); + if (!ref) + { + return; + } + j = DbJson(ref); + + stanzas = JsonValueAsObject(HashMapGet(j, "stanzas")); + if (!stanzas) + { + stanzas = HashMapCreate(); + new_stanzas = true; + } + + if (stanza_id) + { + obj = HashMapCreate(); + HashMapSet(obj, "age", JsonValueInteger(age)); + HashMapSet(obj, "event", JsonValueString(ev)); + JsonValueFree(HashMapSet(stanzas, stanza_id, JsonValueObject(obj))); + + if (new_stanzas) + { + HashMapSet(j, "stanzas", JsonValueObject(stanzas)); + } + } + + events = JsonValueAsObject(HashMapGet(j, "events")); + if (!events) + { + events = HashMapCreate(); + new_events = true; + } + obj = HashMapCreate(); + HashMapSet(obj, "stanza", JsonValueString(stanza_id)); + HashMapSet(obj, "origin", JsonValueString(id)); + HashMapSet(obj, "sender", JsonValueString(sender)); + HashMapSet(obj, "age", JsonValueInteger(age)); + JsonValueFree(HashMapSet(events, ev, JsonValueObject(obj))); + if (new_events) + { + HashMapSet(j, "events", JsonValueObject(events)); + } + + if (id) + { + ids = JsonValueAsObject(HashMapGet(j, "ids")); + if (!ids) + { + ids = HashMapCreate(); + new_ids = true; + } + obj = HashMapCreate(); + HashMapSet(obj, "stanza", JsonValueString(stanza_id)); + HashMapSet(obj, "event", JsonValueString(ev)); + HashMapSet(obj, "sender", JsonValueString(sender)); + HashMapSet(obj, "age", JsonValueInteger(age)); + JsonValueFree(HashMapSet(ids, id, JsonValueObject(obj))); + if (new_ids) + { + HashMapSet(j, "ids", JsonValueObject(ids)); + } + } + DbUnlock(data->db, ref); +} +void ParseePushStanza(ParseeData *data, char *chat_id, char *stanza_id, char *id, char *ev, char *sender) { DbRef *ref; @@ -429,6 +568,36 @@ ParseePushStanza(ParseeData *data, char *chat_id, char *stanza_id, char *id, cha DbUnlock(data->db, ref); } +bool +ParseeVerifyDMStanza(ParseeData *data, char *room_id, char *id) +{ + DbRef *ref = NULL; + HashMap *j = NULL; + HashMap *stanzas = NULL; + bool ret = true; + if (!data || !room_id || !id) + { + return true; + } + + ref = DbLock(data->db, 3, "rooms", room_id, "data"); + j = DbJson(ref); + if (!ref) + { + goto end; + } + + stanzas = JsonValueAsObject(HashMapGet(j, "ids")); + if (!stanzas) + { + goto end; + } + + ret = !HashMapGet(stanzas, id); +end: + DbUnlock(data->db, ref); + return ret; +} bool ParseeVerifyStanza(ParseeData *data, char *chat_id, char *stanza_id) { @@ -490,6 +659,38 @@ end: DbUnlock(data->db, ref); return ret; } +char * +ParseeDMEventFromID(ParseeData *data, char *room_id, char *id) +{ + DbRef *ref = NULL; + HashMap *j = NULL; + HashMap *ids = NULL; + char *ret = NULL; + if (!data || !room_id || !id) + { + return NULL; + } + + ref = DbLock(data->db, 3, "rooms", room_id, "data"); + j = DbJson(ref); + if (!ref) + { + goto end; + } + + ids = JsonValueAsObject(HashMapGet(j, "ids")); + if (!ids) + { + goto end; + } + + ret = JsonValueAsString(JsonGet(ids, 2, id, "event")); + ret = StrDuplicate(ret); +end: + DbUnlock(data->db, ref); + return ret; +} + char * ParseeEventFromSID(ParseeData *data, char *chat_id, char *id) { @@ -521,6 +722,38 @@ end: DbUnlock(data->db, ref); return ret; } +char * +ParseeDMEventFromSID(ParseeData *data, char *room_id, char *id) +{ + DbRef *ref = NULL; + HashMap *j = NULL; + HashMap *ids = NULL; + char *ret = NULL; + if (!data || !room_id || !id) + { + return NULL; + } + + ref = DbLock(data->db, 3, "rooms", room_id, "data"); + j = DbJson(ref); + if (!ref) + { + goto end; + } + + ids = JsonValueAsObject(HashMapGet(j, "stanzas")); + if (!ids) + { + goto end; + } + + ret = JsonValueAsString(JsonGet(ids, 2, id, "event")); + ret = StrDuplicate(ret); +end: + DbUnlock(data->db, ref); + return ret; + +} void ParseeGlobalBan(ParseeData *data, char *user) { diff --git a/src/Parsee/User.c b/src/Parsee/User.c index fb57d15..39b065b 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -550,6 +550,38 @@ ParseeSendPresence(ParseeData *data) DbUnlock(data->db, ref); } bool +ParseeGetDMStanzaInfo(ParseeData *data, char *room_id, char *ev, char **st, char **se) +{ + DbRef *ref = NULL; + HashMap *j = NULL; + HashMap *event = NULL; + bool ret = false; + if (!data || !room_id || !ev || !st || !se) + { + return false; + } + + ref = DbLock(data->db, 3, "rooms", room_id, "data"); + j = DbJson(ref); + if (!ref) + { + goto end; + } + + + event = JsonValueAsObject(JsonGet(j, 2, "events", ev)); + if (!event) + { + goto end; + } + *st = StrDuplicate(JsonValueAsString(HashMapGet(event, "origin"))); + *se = StrDuplicate(JsonValueAsString(HashMapGet(event, "sender"))); + ret = true; +end: + DbUnlock(data->db, ref); + return ret; +} +bool ParseeGetStanzaInfo(ParseeData *data, char *chat_id, char *ev, char **st, char **se) { DbRef *ref = NULL; @@ -582,6 +614,38 @@ end: return ret; } bool +ParseeGetDMOrigin(ParseeData *data, char *room_id, char *ev, char **o) +{ + DbRef *ref = NULL; + HashMap *j = NULL; + HashMap *event = NULL; + bool ret = false; + if (!data || !room_id || !ev || !o) + { + return false; + } + + ref = DbLock(data->db, 3, "rooms", room_id, "data"); + j = DbJson(ref); + if (!ref) + { + goto end; + } + + + event = JsonValueAsObject(JsonGet(j, 2, "events", ev)); + if (!event) + { + goto end; + } + *o = StrDuplicate(JsonValueAsString(HashMapGet(event, "origin"))); + ret = true; +end: + DbUnlock(data->db, ref); + return ret; + +} +bool ParseeGetOrigin(ParseeData *data, char *chat_id, char *ev, char **o) { DbRef *ref = NULL; diff --git a/src/Signal.c b/src/Signal.c index 8289d31..7c11ad0 100644 --- a/src/Signal.c +++ b/src/Signal.c @@ -8,6 +8,7 @@ static HttpServer *server = NULL; static pthread_t xmpp_thr; +static bool valid = true; static XMPPComponent *jabber = NULL; static void @@ -34,6 +35,7 @@ SignalHandler(int signal) Log(LOG_INFO, "Killing thread..."); XMPPKillThread(jabber, "killer"); pthread_join(xmpp_thr, NULL); + valid = false; Log(LOG_INFO, "Stopping server..."); HttpServerStop(server); break; @@ -50,6 +52,8 @@ ParseeInitialiseSignals(HttpServer *s, pthread_t xmpp, XMPPComponent *j) xmpp_thr = xmpp; jabber = j; + valid = true; + sigAction.sa_handler = SignalHandler; sigfillset(&sigAction.sa_mask); sigAction.sa_flags = SA_RESTART; diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c index 9da16e8..2e4e0b7 100644 --- a/src/XMPP/Stanza.c +++ b/src/XMPP/Stanza.c @@ -9,10 +9,18 @@ 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 +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) + if (!comp || !fr || !to || !msg || !ident) { return; } @@ -23,6 +31,7 @@ XMPPSendPlain(XMPPComponent *comp, char *fr, char *to, char *msg, char *type, ch 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); @@ -115,6 +124,8 @@ XMPPSendPlain(XMPPComponent *comp, char *fr, char *to, char *msg, char *type, ch XMLAddChild(body, data); XMLEncode(comp->stream, message); + XMLEncode(StreamStdout(), message); + Log(LOG_INFO, ""); StreamFlush(comp->stream); XMLFreeElement(message); Free(from); diff --git a/src/XMPPThread.c b/src/XMPPThread.c index c759f24..0e0a1fc 100644 --- a/src/XMPPThread.c +++ b/src/XMPPThread.c @@ -15,15 +15,15 @@ #include #define IQ_ADVERT \ - AdvertiseSimple("http://jabber.org/protocol/caps") \ AdvertiseSimple("http://jabber.org/protocol/chatstates") \ + AdvertiseSimple("http://jabber.org/protocol/caps") \ + AdvertiseSimple("urn:xmpp:avatar:metadata+notify") \ AdvertiseSimple("urn:xmpp:message-correct:0") \ AdvertiseSimple("urn:xmpp:reactions:0") \ AdvertiseSimple("urn:xmpp:styling:0") \ AdvertiseSimple("urn:xmpp:reply:0") \ AdvertiseSimple("jabber:x:oob") \ AdvertiseSimple("vcard-temp") \ - AdvertiseSimple("urn:xmpp:avatar:metadata+notify") \ AdvertiseSimple("jabber:iq:version") \ AdvertiseSimple("urn:parsee:x-parsee:0") \ AdvertiseSimple("urn:parsee:jealousy:0") @@ -162,13 +162,112 @@ ParseeWakeupThread(void) pthread_mutex_unlock(&cond_var_lock); } -static void -ParseeDMHandler(char *room, char *from, XMLElement *data, const ParseeConfig *c) +static char * +ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza) { - Free(ASSend( - c, room, from, - "m.room.message", MatrixCreateMessage(data->data) - )); + char *to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to")); + char *from = (HashMapGet(stanza->attrs, "from")); + char *chat_id = ParseeGetFromMUCID(data, from); + char *mroom_id = ParseeGetRoomID(data, chat_id); + char *ret; + + Free(chat_id); + if (mroom_id) + { + Free(to); + return mroom_id; + } + + /* Not a MUC, find the DMd room. */ + ret = ParseeFindDMRoom(data, to, from); + Free(to); + return ret; +} +static char * +ParseeGetEventFromID(ParseeData *data, XMLElement *stanza, char *id) +{ + char *from = (HashMapGet(stanza->attrs, "from")); + char *chat_id = ParseeGetFromMUCID(data, from); + char *ret = ParseeEventFromSID(data, chat_id, id); + char *mroom_id = ParseeGetBridgedRoom(data, stanza); + + if (!ret) + { + Free(ret); + ret = ParseeEventFromID(data, chat_id, id); + } + + Free(chat_id); + if (ret) + { + Free(mroom_id); + return ret; + } + ret = ParseeDMEventFromID(data, mroom_id, id); + Free(mroom_id); + + return ret; +} +static char * +ParseeGetReactedEvent(ParseeData *data, XMLElement *stanza) +{ + XMLElement *reactions = XMLookForTKV(stanza, + "reactions", "xmlns", "urn:xmpp:reactions:0" + ); + char *from = (HashMapGet(stanza->attrs, "from")); + char *reacted_id = reactions ? HashMapGet(reactions->attrs, "id") : NULL; + + return ParseeGetEventFromID(data, stanza, reacted_id); +} + +static void +ParseePushAllStanza(ParseeData *args, XMLElement *stanza, char *event) +{ + char *xmpp_from = HashMapGet(stanza->attrs, "from"); + char *mroom_id = ParseeGetBridgedRoom(args, stanza); + char *chat_id = ParseeGetFromMUCID(args, xmpp_from); + + char *id_str = HashMapGet(stanza->attrs, "id"); + char *s_id_str = XMPPGetStanzaID(stanza); + char *o_id_str = XMPPGetOriginID(stanza); + + if (!chat_id) + { + ParseePushDMStanza( + args, mroom_id, s_id_str, + id_str, event, xmpp_from + ); + } + ParseePushStanza(args, chat_id, s_id_str, id_str, event, xmpp_from); + Free(mroom_id); + Free(chat_id); +} + +static bool +ParseeVerifyAllStanza(ParseeData *args, XMLElement *stanza) +{ + char *to, *room; + char *from = HashMapGet(stanza->attrs, "from"); + char *id = HashMapGet(stanza->attrs, "id"); + char *chat_id = ParseeGetFromMUCID(args, from); + bool ret; + + if (chat_id) + { + char *s_id_str = XMPPGetStanzaID(stanza); + ret = ParseeVerifyStanza(args, chat_id, s_id_str); + + Free(chat_id); + return ret; + } + to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to")); + room = ParseeFindDMRoom(args, to, from); + ret = ParseeVerifyDMStanza(args, chat_id, id); + + Free(room); + Free(to); + + return ret; } /* TODO: Clean up all of this. We are currently separating DMs from MUCs, @@ -225,7 +324,6 @@ MessageStanza(ParseeData *args, XMLElement *stanza) return false; } - /* TODO: On semi-anonymous MUCs, it might be preferable to use a * form of the occupant ID as the base, as it is more unique, and * less prone to trigger the character limit on Matrix. @@ -237,12 +335,7 @@ MessageStanza(ParseeData *args, XMLElement *stanza) room = ParseeFindDMRoom(args, to, from); data = ArrayGet(body->children, 0); - chat_id = ParseeGetFromMUCID(args, from); - mroom_id = ParseeGetRoomID(args, chat_id); - if (room) - { - ParseeDMHandler(room, from_matrix, data, args->config); - } + mroom_id = ParseeGetBridgedRoom(args, stanza); if (mroom_id && !XMPPIsParseeStanza(stanza)) { char *res = ParseeGetResource(from); @@ -253,13 +346,24 @@ MessageStanza(ParseeData *args, XMLElement *stanza) char *event_id = NULL; char *replaced = XMPPGetReplacedID(stanza); char *reply_to = XMPPGetReply(stanza); + bool chat = false; - if (ParseeVerifyStanza(args, chat_id, s_id_str) && !replaced) + if (StrEquals(HashMapGet(stanza->attrs, "type"), "chat")) + { + Free(encoded); + encoded = StrDuplicate(from_matrix); + chat = true; + } + + if (ParseeVerifyAllStanza(args, stanza) && !replaced) { XMLElement *oob, *oob_data; ASRegisterUser(args->config, encoded); - ASSetName(args->config, encoded, res); + if (!chat) + { + ASSetName(args->config, encoded, res); + } ASInvite(args->config, mroom_id, encoded); ASJoin(args->config, mroom_id, encoded); @@ -290,7 +394,7 @@ MessageStanza(ParseeData *args, XMLElement *stanza) char *reacted_id = HashMapGet(reactions->attrs, "id"); Array *react_child = reactions->children; size_t reacts = ArraySize(react_child); - event_id = ParseeEventFromSID(args, chat_id, reacted_id); + event_id = ParseeGetReactedEvent(args, stanza); for (i = 0; i < reacts; i++) { XMLElement *reaction, *react_data; @@ -311,15 +415,13 @@ MessageStanza(ParseeData *args, XMLElement *stanza) { /* TODO: Use HTML-formatted bodies, and respect the fallback * trims the stanza provides us if possible. Element does - * not like raw bodies on replies. Go figure. */ + * not like raw bodies on replies too. Go figure. */ size_t off = reply_to ? ParseeFindDatastart(data->data) : 0; HashMap *ev = MatrixCreateMessage(data->data + off); if (reply_to) { - char *reply_id = ParseeEventFromSID( - args, chat_id, reply_to - ); + char *reply_id = ParseeGetEventFromID(args, stanza, reply_to); MatrixSetReply(ev, reply_id); Free(reply_id); } @@ -328,16 +430,17 @@ MessageStanza(ParseeData *args, XMLElement *stanza) "m.room.message", ev ); } - ParseePushStanza(args, chat_id, s_id_str, id_str, event_id, from); + ParseePushAllStanza(args, stanza, event_id); Free(event_id); } else if (replaced) { - event_id = ParseeEventFromID(args, chat_id, replaced); + event_id = ParseeGetEventFromID(args, stanza, replaced); Free(ASSend( args->config, mroom_id, encoded, "m.room.message", MatrixCreateReplace(event_id, data->data) )); + ParseePushAllStanza(args, stanza, event_id); Free(event_id); } @@ -345,19 +448,16 @@ MessageStanza(ParseeData *args, XMLElement *stanza) Free(res); Free(encoded); } - else if (mroom_id) + else { XMLElement *parsee = XMLookForUnique(stanza, "x-parsee"); XMLElement *event = XMLookForUnique(parsee, "event-id"); XMLElement *e_d = ArrayGet(event ? event->children : NULL, 0); char *s_id_str = XMPPGetStanzaID(stanza); char *id_str = HashMapGet(stanza->attrs, "id"); - if (ParseeVerifyStanza(args, chat_id, s_id_str)) - { - ParseePushStanza(args, chat_id, s_id_str, id_str, e_d->data, from); - } + + ParseePushAllStanza(args, stanza, e_d->data); } - Free(chat_id); Free(mroom_id); Free(from_matrix); Free(decode_from); @@ -579,6 +679,7 @@ ParseeXMPPThread(void *argp) const char *killer = "killer"; const char *suspend="suspend"; from = HashMapGet(stanza->attrs, "from"); + Log(LOG_INFO, "Killer."); if (!strncmp(from, killer, strlen(killer))) { XMLFreeElement(stanza); diff --git a/src/include/Parsee.h b/src/include/Parsee.h index c3a86c1..9c8ee2a 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -159,13 +159,16 @@ extern char * ParseeGetMUCID(ParseeData *, char *chat_id); /* Pushes a stanza ID to a chat ID */ extern void ParseePushStanza(ParseeData *, char *chat_id, char *stanza_id, char *origin_id, char *event, char *sender); +extern void ParseePushDMStanza(ParseeData *, char *room_id, char *stanza_id, char *origin_id, char *event, char *sender); /* Checks if a stanza is not duplicated in a chat ID */ extern bool ParseeVerifyStanza(ParseeData *, char *chat_id, char *stanza_id); /* Gets the stanza ID and sender of an event */ extern bool ParseeGetStanzaInfo(ParseeData *, char *c_id, char *e, char **st, char **se); +extern bool ParseeGetDMStanzaInfo(ParseeData *, char *r_id, char *e, char **st, char **se); extern bool ParseeGetOrigin(ParseeData *data, char *chat_id, char *ev, char **o); +extern bool ParseeGetDMOrigin(ParseeData *data, char *chat_id, char *ev, char **o); /* Sends presence requests for every MUC around as a fake JID */ extern void ParseeSendPresence(ParseeData *); @@ -186,6 +189,9 @@ extern char * ParseeXMPPify(HashMap *event); extern char * ParseeEventFromID(ParseeData *d, char *c_id, char *ori_id); extern char * ParseeEventFromSID(ParseeData *d, char *c_id, char *ori_id); +extern char * ParseeDMEventFromID(ParseeData *d, char *r_id, char *ori_id); +extern char * ParseeDMEventFromSID(ParseeData *d, char *r_id, char *ori_id); + /* Gets a Parsee "shim" link to an MXC, usable as unauth for a limited time */ extern char * ParseeToUnauth(ParseeData *data, char *mxc); @@ -201,4 +207,7 @@ extern void ParseeGlobalBan(ParseeData *, char *user); /* Verifies if a user was globally banned. If so, then apply actions to the * room ID */ extern bool ParseeManageBan(ParseeData *, char *user, char *room); + +/* Same as ParseeVerifyStanza, but DMs */ +extern bool ParseeVerifyDMStanza(ParseeData *data, char *room_id, char *id); #endif diff --git a/src/include/Routes.h b/src/include/Routes.h index e7c55db..88816b3 100644 --- a/src/include/Routes.h +++ b/src/include/Routes.h @@ -30,6 +30,11 @@ typedef struct ParseeCmdArg { "set-pl", CmdSetPL, \ "Sets the power level in a Parsee room" \ ) \ + X_COMMAND( \ + "set-min-pl", CmdSetMin, \ + "Sets the power level to send a specific event " \ + "in a Parsee room" \ + ) \ X_COMMAND( \ "help", CmdHelp, \ "Shows the command list" \ diff --git a/src/include/XMPP.h b/src/include/XMPP.h index 3d39718..9a3d5e9 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -29,6 +29,7 @@ extern void XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc); /* TODO: XMPP stuff, I don't fucking know, I'm not a Jabbernerd. */ extern void XMPPSendPlain(XMPPComponent *comp, char *fr, char *to, char *msg, char *type, char *rst, char *rse, char *event_id, char *oob, char *id); +extern void XMPPSendPlainID(XMPPComponent *comp, char *fr, char *to, char *msg, char *type, char *rst, char *rse, char *event_id, char *oob, char *id, char *sid); /* Closes a raw component stream. */ extern void XMPPEndCompStream(XMPPComponent *stream);