mirror of
https://forge.fsky.io/lda/Parsee.git
synced 2026-03-13 15:15:10 +00:00
[ADD/WIP] Editing support XMPP->Matrix
This commit is contained in:
parent
771c3271ad
commit
ae740878c8
13 changed files with 249 additions and 106 deletions
28
src/Events.c
28
src/Events.c
|
|
@ -129,3 +129,31 @@ MatrixGetReply(HashMap *event)
|
|||
"event_id")
|
||||
));
|
||||
}
|
||||
HashMap *
|
||||
MatrixCreateReplace(char *event, char *body)
|
||||
{
|
||||
HashMap *map;
|
||||
HashMap *new;
|
||||
HashMap *rel;
|
||||
if (!body || !event)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
map = HashMapCreate();
|
||||
HashMapSet(map, "msgtype", JsonValueString("m.text"));
|
||||
HashMapSet(map, "body", JsonValueString(body));
|
||||
|
||||
new = HashMapCreate();
|
||||
HashMapSet(new, "msgtype", JsonValueString("m.text"));
|
||||
HashMapSet(new, "body", JsonValueString(body));
|
||||
|
||||
rel = HashMapCreate();
|
||||
HashMapSet(rel, "rel_type", JsonValueString("m.replace"));
|
||||
HashMapSet(rel, "event_id", JsonValueString(event));
|
||||
|
||||
HashMapSet(map, "m.new_content", JsonValueObject(new));
|
||||
HashMapSet(map, "m.relates_to", JsonValueObject(rel));
|
||||
|
||||
return map;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ ParseeMemberHandler(ParseeData *data, HashMap *event)
|
|||
char *sender = GrabString(event, 1, "sender");
|
||||
char *chat_id;
|
||||
const ParseeConfig *conf = data->config;
|
||||
Log(LOG_INFO, "Membership '%s'->'%s'", state_key, membership);
|
||||
|
||||
if (StrEquals(membership, "invite") && ParseeIsPuppet(conf, state_key))
|
||||
{
|
||||
|
|
@ -84,11 +83,6 @@ ParseeMessageHandler(ParseeData *data, HashMap *event)
|
|||
return;
|
||||
}
|
||||
|
||||
if (reply_id)
|
||||
{
|
||||
Log(LOG_INFO, "reply=%s", reply_id);
|
||||
}
|
||||
|
||||
ref = DbLock(data->db, 3, "rooms", id, "data");
|
||||
json = DbJson(ref);
|
||||
direct = JsonValueAsBoolean(HashMapGet(json, "is_direct"));
|
||||
|
|
@ -125,8 +119,6 @@ ParseeMessageHandler(ParseeData *data, HashMap *event)
|
|||
if (reply_id)
|
||||
{
|
||||
ParseeGetStanzaInfo(data, chat_id, reply_id, &stanza, &sender);
|
||||
|
||||
Log(LOG_INFO, "Replying to %s by %s", stanza, sender);
|
||||
}
|
||||
XMPPJoinMUC(jabber, jid, rev);
|
||||
XMPPSendPlain(
|
||||
|
|
|
|||
|
|
@ -285,3 +285,137 @@ ParseeXMPPify(HashMap *event)
|
|||
|
||||
return xepd;
|
||||
}
|
||||
void
|
||||
ParseePushStanza(ParseeData *data, char *chat_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 || !chat_id || !stanza_id || !ev || !sender)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ref = DbLock(data->db, 2, "chats", chat_id);
|
||||
j = DbJson(ref);
|
||||
if (!ref)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
stanzas = JsonValueAsObject(HashMapGet(j, "stanzas"));
|
||||
if (!stanzas)
|
||||
{
|
||||
stanzas = HashMapCreate();
|
||||
new_stanzas = true;
|
||||
}
|
||||
|
||||
obj = HashMapCreate();
|
||||
HashMapSet(obj, "age", JsonValueInteger(age));
|
||||
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));
|
||||
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));
|
||||
JsonValueFree(HashMapSet(ids, id, JsonValueObject(obj)));
|
||||
if (new_ids)
|
||||
{
|
||||
HashMapSet(j, "ids", JsonValueObject(ids));
|
||||
}
|
||||
}
|
||||
DbUnlock(data->db, ref);
|
||||
}
|
||||
|
||||
bool
|
||||
ParseeVerifyStanza(ParseeData *data, char *chat_id, char *stanza_id)
|
||||
{
|
||||
DbRef *ref = NULL;
|
||||
HashMap *j = NULL;
|
||||
HashMap *stanzas = NULL;
|
||||
bool ret = true;
|
||||
if (!data || !chat_id || !stanza_id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ref = DbLock(data->db, 2, "chats", chat_id);
|
||||
j = DbJson(ref);
|
||||
if (!ref)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
stanzas = JsonValueAsObject(HashMapGet(j, "stanzas"));
|
||||
if (!stanzas)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = !HashMapGet(stanzas, stanza_id);
|
||||
end:
|
||||
DbUnlock(data->db, ref);
|
||||
return ret;
|
||||
}
|
||||
char *
|
||||
ParseeEventFromID(ParseeData *data, char *chat_id, char *id)
|
||||
{
|
||||
DbRef *ref = NULL;
|
||||
HashMap *j = NULL;
|
||||
HashMap *ids = NULL;
|
||||
char *ret = NULL;
|
||||
if (!data || !chat_id || !id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ref = DbLock(data->db, 2, "chats", chat_id);
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -540,89 +540,6 @@ ParseeGetMUCID(ParseeData *data, char *chat_id)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
ParseePushStanza(ParseeData *data, char *chat_id, char *stanza_id, char *ev, char *sender)
|
||||
{
|
||||
DbRef *ref;
|
||||
HashMap *j;
|
||||
HashMap *stanzas, *obj, *events;
|
||||
bool new_stanzas = false, new_events = false;
|
||||
uint64_t age = UtilTsMillis();
|
||||
if (!data || !chat_id || !stanza_id || !ev || !sender)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ref = DbLock(data->db, 2, "chats", chat_id);
|
||||
j = DbJson(ref);
|
||||
if (!ref)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
stanzas = JsonValueAsObject(HashMapGet(j, "stanzas"));
|
||||
if (!stanzas)
|
||||
{
|
||||
stanzas = HashMapCreate();
|
||||
new_stanzas = true;
|
||||
}
|
||||
|
||||
obj = HashMapCreate();
|
||||
HashMapSet(obj, "age", JsonValueInteger(age));
|
||||
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, "sender", JsonValueString(sender));
|
||||
JsonValueFree(HashMapSet(events, ev, JsonValueObject(obj)));
|
||||
if (new_events)
|
||||
{
|
||||
HashMapSet(j, "events", JsonValueObject(events));
|
||||
}
|
||||
DbUnlock(data->db, ref);
|
||||
}
|
||||
|
||||
bool
|
||||
ParseeVerifyStanza(ParseeData *data, char *chat_id, char *stanza_id)
|
||||
{
|
||||
DbRef *ref = NULL;
|
||||
HashMap *j = NULL;
|
||||
HashMap *stanzas = NULL;
|
||||
bool ret = true;
|
||||
if (!data || !chat_id || !stanza_id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ref = DbLock(data->db, 2, "chats", chat_id);
|
||||
j = DbJson(ref);
|
||||
if (!ref)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
stanzas = JsonValueAsObject(HashMapGet(j, "stanzas"));
|
||||
if (!stanzas)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = !HashMapGet(stanzas, stanza_id);
|
||||
end:
|
||||
DbUnlock(data->db, ref);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
ParseeSendPresence(ParseeData *data)
|
||||
|
|
|
|||
|
|
@ -35,9 +35,7 @@ RouteHead(RouteTxns, arr, argp)
|
|||
for (i = 0; i < ArraySize(events); i++)
|
||||
{
|
||||
HashMap *event = JsonValueAsObject(ArrayGet(events, i));
|
||||
event = JsonDuplicate(event);
|
||||
ParseeEventHandler(args->data, event);
|
||||
JsonFree(event);
|
||||
}
|
||||
|
||||
/* TODO: Store TXN ID somewhere so that we can commit
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ SignalHandler(int signal)
|
|||
Log(LOG_INFO, "Killing thread...");
|
||||
XMPPKillThread(jabber, "killer");
|
||||
pthread_join(xmpp_thr, NULL);
|
||||
Log(LOG_INFO, "Stopping server...");
|
||||
HttpServerStop(server);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ XMLookForTKV(XMLElement *parent, char *tag, char *k, char *v)
|
|||
{
|
||||
size_t i;
|
||||
|
||||
if (!parent || !tag || !k || !v)
|
||||
if (!parent || !k || !v)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -147,9 +147,12 @@ XMLookForTKV(XMLElement *parent, char *tag, char *k, char *v)
|
|||
XMLElement *child = ArrayGet(parent->children, i);
|
||||
HashMap *attrs = child->attrs;
|
||||
char *value = HashMapGet(attrs, k);
|
||||
if (StrEquals(child->name, tag) && StrEquals(value, v))
|
||||
if (StrEquals(child->name, tag) || !tag)
|
||||
{
|
||||
return child;
|
||||
if (StrEquals(value, v))
|
||||
{
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -730,12 +730,14 @@ XMLParseAttQuote(XMLexer *lexer)
|
|||
char *code = NULL;
|
||||
int c2;
|
||||
int p2 = XMLInitialiseBuffer(lexer);
|
||||
while ((c2 = XMLGetc(lexer)) && c2 != EOF)
|
||||
int j = 0;
|
||||
while ((c2 = XMLGetc(lexer)) && c2 != EOF && j < 8)
|
||||
{
|
||||
if (c2 == ';')
|
||||
{
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
if (c2 != ';')
|
||||
{
|
||||
|
|
@ -775,12 +777,14 @@ XMLParseAttDouble(XMLexer *lexer)
|
|||
char *code = NULL;
|
||||
int c2;
|
||||
int p2 = XMLInitialiseBuffer(lexer);
|
||||
while ((c2 = XMLGetc(lexer)) && c2 != EOF)
|
||||
int j = 0;
|
||||
while ((c2 = XMLGetc(lexer)) && c2 != EOF && j < 8)
|
||||
{
|
||||
if (c2 == ';')
|
||||
{
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
if (c2 != ';')
|
||||
{
|
||||
|
|
|
|||
|
|
@ -199,3 +199,38 @@ XMPPIsParseeStanza(XMLElement *stanza)
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ MessageStanza(ParseeData *args, XMLElement *stanza)
|
|||
|
||||
XMLElement *body = NULL;
|
||||
XMLElement *data = NULL;
|
||||
XMLElement *stanza_id = NULL;
|
||||
|
||||
char *to, *room, *from, *from_matrix;
|
||||
char *chat_id, *mroom_id;
|
||||
|
|
@ -51,7 +50,6 @@ MessageStanza(ParseeData *args, XMLElement *stanza)
|
|||
XMLFreeElement(stanza);
|
||||
return false;
|
||||
}
|
||||
stanza_id = XMLookForUnique(stanza, "stanza-id");
|
||||
|
||||
to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to"));
|
||||
from = HashMapGet(stanza->attrs, "from");
|
||||
|
|
@ -69,12 +67,15 @@ MessageStanza(ParseeData *args, XMLElement *stanza)
|
|||
if (mroom_id && !XMPPIsParseeStanza(stanza))
|
||||
{
|
||||
char *res = ParseeGetResource(from);
|
||||
char *encoded = ParseeEncodeJID(args->config, from, false);
|
||||
char *s_id_str = HashMapGet(stanza_id->attrs, "id");
|
||||
char *encoded = ParseeEncodeJID(args->config, from, false);
|
||||
char *s_id_str = XMPPGetStanzaID(stanza);
|
||||
char *o_id_str = XMPPGetOriginID(stanza);
|
||||
char *id_str = HashMapGet(stanza->attrs, "id");
|
||||
char *event_id;
|
||||
char *replaced = XMPPGetReplacedID(stanza);
|
||||
|
||||
/* TODO: Create smarter puppet names */
|
||||
if (ParseeVerifyStanza(args, chat_id, s_id_str))
|
||||
if (ParseeVerifyStanza(args, chat_id, s_id_str) && !replaced)
|
||||
{
|
||||
XMLElement *oob, *oob_data;
|
||||
|
||||
|
|
@ -108,7 +109,18 @@ MessageStanza(ParseeData *args, XMLElement *stanza)
|
|||
"m.room.message", MatrixCreateMessage(data->data)
|
||||
);
|
||||
}
|
||||
ParseePushStanza(args, chat_id, s_id_str, event_id, from);
|
||||
ParseePushStanza(args, chat_id, s_id_str, id_str, event_id, from);
|
||||
Free(event_id);
|
||||
}
|
||||
else if (replaced)
|
||||
{
|
||||
event_id = ParseeEventFromID(args, chat_id, replaced);
|
||||
Log(LOG_WARNING, "RETRACTION REQUEST TO %s->%s", replaced, event_id);
|
||||
Free(ASSend(
|
||||
args->config, mroom_id, encoded,
|
||||
"m.room.message", MatrixCreateReplace(event_id, data->data)
|
||||
));
|
||||
|
||||
Free(event_id);
|
||||
}
|
||||
|
||||
|
|
@ -154,8 +166,10 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza)
|
|||
} \
|
||||
while (0)
|
||||
|
||||
AdvertiseSimple("urn:xmpp:reply:0");
|
||||
AdvertiseSimple("urn:xmpp:message-correct:0");
|
||||
AdvertiseSimple("urn:xmpp:styling:0");
|
||||
AdvertiseSimple("urn:xmpp:reply:0");
|
||||
AdvertiseSimple("urn:xmpp:sid:0");
|
||||
|
||||
AdvertiseSimple("urn:parsee:x-parsee:0");
|
||||
AdvertiseSimple("urn:parsee:jealousy:0");
|
||||
|
|
@ -234,6 +248,7 @@ ParseeXMPPThread(void *argp)
|
|||
from = HashMapGet(stanza->attrs, "from");
|
||||
if (!strncmp(from, killer, strlen(killer)))
|
||||
{
|
||||
Log(LOG_INFO, "Killer detected.");
|
||||
XMLFreeElement(stanza);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ extern HashMap * MatrixCreateNotice(char *body);
|
|||
/* Creates the content for a normal message. */
|
||||
extern HashMap * MatrixCreateMessage(char *body);
|
||||
|
||||
/* Creates the content for a replace message. */
|
||||
extern HashMap * MatrixCreateReplace(char *event, char *body);
|
||||
|
||||
/* Creates the content for a media file. */
|
||||
extern HashMap * MatrixCreateMedia(char *mxc, char *body, char *mime);
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ extern char * ParseeGetRoomID(ParseeData *, char *chat_id);
|
|||
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 *event, char *sender);
|
||||
extern void ParseePushStanza(ParseeData *, char *chat_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);
|
||||
|
|
@ -167,4 +167,7 @@ extern int ParseeFindDatastart(char *data);
|
|||
|
||||
/* XMPP-ifies a message event to XEP-0393 if possible. */
|
||||
extern char * ParseeXMPPify(HashMap *event);
|
||||
|
||||
/* Finds an event ID from an ID in the stanza's attributes */
|
||||
extern char * ParseeEventFromID(ParseeData *d, char *c_id, char *ori_id);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -61,4 +61,14 @@ extern void XMPPFreeMUCInfo(MUCInfo info);
|
|||
/* Checks if a stanza has an x-parsee element */
|
||||
extern bool XMPPIsParseeStanza(XMLElement *);
|
||||
|
||||
/* Returns the stanza ID of a stanza, if existent */
|
||||
extern char * XMPPGetStanzaID(XMLElement *);
|
||||
|
||||
/* Returns the origin ID of a stanza, if existent */
|
||||
extern char * XMPPGetOriginID(XMLElement *);
|
||||
|
||||
/* Returns the origin ID of the replaced stanza, if the current one
|
||||
* is a replacement notice */
|
||||
extern char * XMPPGetReplacedID(XMLElement *);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue