mirror of
https://forge.fsky.io/lda/Parsee.git
synced 2026-03-13 16:45:10 +00:00
[ADD/WIP] Start unifying DMs and MUCs
I really need to dispatch XMPP stanza management.
This commit is contained in:
parent
6b0f08c49e
commit
5f2c3a9cb8
10 changed files with 570 additions and 87 deletions
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <AS.h>
|
||||
|
||||
#include <Cytoplasm/Log.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
DbUnlock(data->db, ref);
|
||||
else
|
||||
{
|
||||
char *name, *rev, *stanza;
|
||||
/* Try to find the chat ID */
|
||||
muc_id = ParseeGetMUCID(data, chat_id);
|
||||
if (!chat_id)
|
||||
{
|
||||
Free(reply_id);
|
||||
Free(xepd);
|
||||
return;
|
||||
goto end;
|
||||
}
|
||||
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);
|
||||
xmppified_user = ParseeEncodeMXID(m_sender);
|
||||
|
||||
char *unedited_id = MatrixGetEdit(event);
|
||||
char *origin_id = NULL;
|
||||
/* TODO: Check the name's validity */
|
||||
name = ASGetName(data->config, id, m_sender);
|
||||
rev = StrConcat(4, muc_id, "/", name, "[p]");
|
||||
|
||||
XMPPJoinMUC(jabber, xmppified_user, rev);
|
||||
|
||||
to = muc_id;
|
||||
|
||||
Free(name);
|
||||
Free(rev);
|
||||
}
|
||||
if (reply_id)
|
||||
{
|
||||
ParseeGetStanzaInfo(data, chat_id, reply_id, &stanza, &sender);
|
||||
/* 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)
|
||||
{
|
||||
ParseeGetOrigin(data, chat_id, unedited_id, &origin_id);
|
||||
if (!ParseeGetOrigin(data, chat_id, unedited_id, &origin_id))
|
||||
{
|
||||
ParseeGetDMOrigin(data, 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
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
Free(rev);
|
||||
Free(name);
|
||||
/* 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(to);
|
||||
Free(reply_id);
|
||||
Free(xepd);
|
||||
Free(stanza);
|
||||
Free(sender);
|
||||
Free(unauth);
|
||||
Free(origin_id);
|
||||
Free(unedited_id);
|
||||
}
|
||||
Free(chat_id);
|
||||
Free(muc_id);
|
||||
Free(jid);
|
||||
Free(reply_id);
|
||||
Free(xepd);
|
||||
|
||||
DbUnlock(data->db, ref);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -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); \
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
159
src/XMPPThread.c
159
src/XMPPThread.c
|
|
@ -15,15 +15,15 @@
|
|||
#include <AS.h>
|
||||
|
||||
#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);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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" \
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue