forked from Telodendria/Telodendria
[ADD/WIP/UNTESTED] Start verifying membership, tested hashing
Some checks failed
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Has been cancelled
Some checks failed
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Has been cancelled
This commit is contained in:
parent
001b4821fe
commit
9bc36f324a
5 changed files with 408 additions and 37 deletions
|
@ -168,10 +168,15 @@ CanonicalJsonEncode(HashMap * object, Stream * out)
|
||||||
static ssize_t
|
static ssize_t
|
||||||
StringIoRead(void *cookie, void *buf, size_t count)
|
StringIoRead(void *cookie, void *buf, size_t count)
|
||||||
{
|
{
|
||||||
|
(void) cookie;
|
||||||
|
(void) buf;
|
||||||
|
(void) count;
|
||||||
return -1; /* TODO: Consider reading properly */
|
return -1; /* TODO: Consider reading properly */
|
||||||
}
|
}
|
||||||
static ssize_t
|
static ssize_t
|
||||||
StringIoWrite(void *c, void *buf, size_t count)
|
StringIoWrite(void *c, void *buf, size_t count)
|
||||||
|
{
|
||||||
|
if (count > 0)
|
||||||
{
|
{
|
||||||
char **str = c;
|
char **str = c;
|
||||||
char *stringised = Malloc(count + 1);
|
char *stringised = Malloc(count + 1);
|
||||||
|
@ -185,6 +190,7 @@ StringIoWrite(void *c, void *buf, size_t count)
|
||||||
Free(*str);
|
Free(*str);
|
||||||
}
|
}
|
||||||
*str = new;
|
*str = new;
|
||||||
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
static const IoFunctions Functions = {
|
static const IoFunctions Functions = {
|
||||||
|
@ -202,6 +208,7 @@ CanonicalJsonHash(HashMap *json)
|
||||||
Io *string_writer = IoCreate(&string, Functions);
|
Io *string_writer = IoCreate(&string, Functions);
|
||||||
Stream *io_stream = StreamIo(string_writer);
|
Stream *io_stream = StreamIo(string_writer);
|
||||||
CanonicalJsonEncode(json, io_stream);
|
CanonicalJsonEncode(json, io_stream);
|
||||||
|
StreamFlush(io_stream);
|
||||||
|
|
||||||
sha = Sha256(string);
|
sha = Sha256(string);
|
||||||
shastr = ShaToHex(sha);
|
shastr = ShaToHex(sha);
|
||||||
|
|
367
src/Room.c
367
src/Room.c
|
@ -23,9 +23,11 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Cytoplasm/Json.h"
|
#include <Cytoplasm/Array.h>
|
||||||
#include "Cytoplasm/Stream.h"
|
#include <Cytoplasm/Json.h>
|
||||||
|
/*#include "Cytoplasm/Stream.h"*/
|
||||||
#include "Parser.h"
|
#include "Parser.h"
|
||||||
|
#include "User.h"
|
||||||
#include <Room.h>
|
#include <Room.h>
|
||||||
|
|
||||||
#include <Cytoplasm/Memory.h>
|
#include <Cytoplasm/Memory.h>
|
||||||
|
@ -42,7 +44,10 @@
|
||||||
#include <State.h>
|
#include <State.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define IsState(p, typ, key) (StrEquals(p->type, typ) && \
|
||||||
|
StrEquals(p->state_key, key))
|
||||||
struct Room
|
struct Room
|
||||||
{
|
{
|
||||||
Db *db;
|
Db *db;
|
||||||
|
@ -84,7 +89,6 @@ RoomCreate(Db * db, User *user, RoomCreateRequest * req)
|
||||||
room->id = GenerateRoomId(); /* TODO: Check config. */
|
room->id = GenerateRoomId(); /* TODO: Check config. */
|
||||||
room->version = version_num;
|
room->version = version_num;
|
||||||
|
|
||||||
/* TODO: A room is *not just* its state? */
|
|
||||||
room->ref = DbCreate(db, 3, "rooms", room->id, "state");
|
room->ref = DbCreate(db, 3, "rooms", room->id, "state");
|
||||||
|
|
||||||
/* TODO: Populate room with information */
|
/* TODO: Populate room with information */
|
||||||
|
@ -185,23 +189,12 @@ PopulateEventV1(Room * room, HashMap * event, PduV1 * pdu)
|
||||||
pdu->content = JsonDuplicate(event); /* Copy the original JSON data */
|
pdu->content = JsonDuplicate(event); /* Copy the original JSON data */
|
||||||
|
|
||||||
/* TODO: Signature and alldat. */
|
/* TODO: Signature and alldat. */
|
||||||
|
|
||||||
|
(void) room;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
static bool
|
static bool
|
||||||
PopulateEventV3(Room * room, HashMap * event, PduV3 *pdu)
|
AuthoriseCreateV1(PduV1 pdu)
|
||||||
{
|
|
||||||
char *unused;
|
|
||||||
if (PduV3FromJson(event, pdu, &unused))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: Create a PDU of our own, signed and everything.
|
|
||||||
* https://telodendria.io/blog/matrix-protocol-overview
|
|
||||||
* has some ideas on how this could be done(up until stage 5). */
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
static AuthoriseCreateV1(PduV1 pdu)
|
|
||||||
{
|
{
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
CommonID sender = { 0 }, room_id = { 0 };
|
CommonID sender = { 0 }, room_id = { 0 };
|
||||||
|
@ -244,23 +237,298 @@ finish:
|
||||||
CommonIDFree(room_id);
|
CommonIDFree(room_id);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
AuthoriseEventV1(PduV1 pdu)
|
ValidAuthEventV1(PduV1 *auth_pdu, PduV1 *pdu)
|
||||||
{
|
{
|
||||||
|
if (IsState(auth_pdu, "m.room.create", ""))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (IsState(auth_pdu, "m.room.power_levels", ""))
|
||||||
|
{
|
||||||
|
/* TODO: Check if it's the latest in terms of [pdu] */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (StrEquals(pdu->type, "m.room.member"))
|
||||||
|
{
|
||||||
|
char *membership =
|
||||||
|
JsonValueAsString(JsonGet(pdu->content, 1, "membership"));
|
||||||
|
if (IsState(auth_pdu, "m.room.member", pdu->sender))
|
||||||
|
{
|
||||||
|
/* TODO: Check if it's the latest in terms of [pdu] */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((StrEquals(membership, "join") ||
|
||||||
|
StrEquals(membership, "invite")) &&
|
||||||
|
IsState(auth_pdu, "m.room.join_rules",""))
|
||||||
|
{
|
||||||
|
/* TODO: Check if it's the latest in terms of [pdu] */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/* TODO: The rest.
|
||||||
|
* https://spec.matrix.org/v1.7/server-server-api/#auth-events-selection */
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static bool
|
||||||
|
VerifyPDUV1(PduV1 *auth_pdu)
|
||||||
|
{
|
||||||
|
/* TODO:
|
||||||
|
* https://spec.matrix.org/v1.7/server-server-api/
|
||||||
|
* #checks-performed-on-receipt-of-a-pdu */
|
||||||
|
(void) auth_pdu;
|
||||||
|
return false; /* This only shows whenever an event was rejected, not
|
||||||
|
* soft-failed */
|
||||||
|
}
|
||||||
|
static bool
|
||||||
|
ConsiderAuthEventsV1(Room * room, PduV1 pdu)
|
||||||
|
{
|
||||||
|
char *ignored;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
HashMap *state_keytype;
|
||||||
|
state_keytype = HashMapCreate();
|
||||||
|
for (i = 0; i < ArraySize(pdu.auth_events); i++)
|
||||||
|
{
|
||||||
|
char *event_id = ArrayGet(pdu.auth_events, i);
|
||||||
|
HashMap *event = RoomEventFetch(room, event_id);
|
||||||
|
PduV1 auth_pdu;
|
||||||
|
|
||||||
|
char *key_type_id;
|
||||||
|
|
||||||
|
if (!PduV1FromJson(event, &auth_pdu, &ignored))
|
||||||
|
{
|
||||||
|
HashMapFree(event);
|
||||||
|
return false; /* Yeah... we aren't doing that. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Find a better way to do this. Using HashMaps as sets
|
||||||
|
* *works*, but it's not the best of ideas here. Also, we're using
|
||||||
|
* strings to compare things, which yeah. */
|
||||||
|
key_type_id = StrConcat(3, auth_pdu.type, ",", auth_pdu.state_key);
|
||||||
|
|
||||||
|
if (HashMapGet(state_keytype, key_type_id))
|
||||||
|
{
|
||||||
|
/* Duplicate found! We actually ignore it's actual value. */
|
||||||
|
HashMapFree(event);
|
||||||
|
PduV1Free(&auth_pdu);
|
||||||
|
|
||||||
|
HashMapFree(state_keytype);
|
||||||
|
Free(key_type_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Whenever event is valid or not really doesn't matter, as we're
|
||||||
|
* not using it's value anywhere. */
|
||||||
|
HashMapSet(state_keytype, key_type_id, event);
|
||||||
|
Free(key_type_id);
|
||||||
|
|
||||||
|
/* Step 2.2: If there are entries whose type and state_key don't
|
||||||
|
* match those specified by the auth events selection algorithm
|
||||||
|
* described in the server specification, reject. */
|
||||||
|
if (!ValidAuthEventV1(&auth_pdu, &pdu))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Step 2.3: If there are entries which were themselves rejected
|
||||||
|
* under the checks performed on receipt of a PDU, reject.
|
||||||
|
* TODO */
|
||||||
|
if (!VerifyPDUV1(&auth_pdu))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 2.4: If there is no m.room.create event among the entries,
|
||||||
|
* reject. */
|
||||||
|
|
||||||
|
HashMapFree(event);
|
||||||
|
PduV1Free(&auth_pdu);
|
||||||
|
}
|
||||||
|
HashMapFree(state_keytype);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static bool
|
||||||
|
VerifyServers(char *id1, char *id2)
|
||||||
|
{
|
||||||
|
CommonID cid1;
|
||||||
|
CommonID cid2;
|
||||||
|
|
||||||
|
char *str1;
|
||||||
|
char *str2;
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
if (!ParseCommonID(id1, &cid1))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!ParseCommonID(id2, &cid2))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
str1 = ParserRecomposeServerPart(cid1.server);
|
||||||
|
str2 = ParserRecomposeServerPart(cid2.server);
|
||||||
|
|
||||||
|
if (StrEquals(str1, str2))
|
||||||
|
{
|
||||||
|
ret = true;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
Free(str1);
|
||||||
|
Free(str2);
|
||||||
|
CommonIDFree(cid1);
|
||||||
|
CommonIDFree(cid2);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
static bool
|
||||||
|
AuthoriseAliasV1(PduV1 pdu)
|
||||||
|
{
|
||||||
|
/* Step 4.1: If event has no state_key, reject. */
|
||||||
|
if (!pdu.state_key || StrEquals(pdu.state_key, ""))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Step 4.2: If sender's domain doesn't matches state_key, reject. */
|
||||||
|
if (!VerifyServers(pdu.state_key, pdu.sender))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 4.3: Otherwise, allow. */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static bool
|
||||||
|
AuthorizeJoinMembershipV1(Room * room, PduV1 pdu)
|
||||||
|
{
|
||||||
|
/* Step 5.2.1: If the only previous event is an m.room.create and the
|
||||||
|
* state_key is the creator, allow. */
|
||||||
|
Array *prev = pdu.prev_events;
|
||||||
|
if (ArraySize(prev) == 1)
|
||||||
|
{
|
||||||
|
char *prev_id = ArrayGet(prev, 0);
|
||||||
|
char *ignored;
|
||||||
|
HashMap *prev = RoomEventFetch(room, prev_id);
|
||||||
|
PduV1 prev_pdu;
|
||||||
|
|
||||||
|
if (prev && PduV1FromJson(prev, &prev_pdu, &ignored))
|
||||||
|
{
|
||||||
|
if (StrEquals(prev_pdu.type, "m.room.create") &&
|
||||||
|
StrEquals(prev_pdu.sender, pdu.state_key))
|
||||||
|
{
|
||||||
|
PduV1Free(&prev_pdu);
|
||||||
|
JsonFree(prev);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
PduV1Free(&prev_pdu);
|
||||||
|
}
|
||||||
|
JsonFree(prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 5.2.2: If the sender does not match state_key, reject. */
|
||||||
|
if (!StrEquals(pdu.sender, pdu.state_key))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Step 5.2.3: If the sender is banned, reject. */
|
||||||
|
/* TODO */
|
||||||
|
|
||||||
|
/* Step 5.2.4: If the join_rule is invite then allow if membership
|
||||||
|
* state is invite or join. */
|
||||||
|
/* Step 5.2.6: Otherwise, reject. */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static bool
|
||||||
|
AuthoriseMemberV1(Room * room, PduV1 pdu)
|
||||||
|
{
|
||||||
|
JsonValue *membership;
|
||||||
|
char *membership_str;
|
||||||
|
/* Step 5.1: If there is no state_key property, or no membership
|
||||||
|
* property in content, reject. */
|
||||||
|
if (!pdu.state_key ||
|
||||||
|
StrEquals(pdu.state_key, "") ||
|
||||||
|
!(membership = JsonGet(pdu.content, 1, "membership")))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (JsonValueType(membership) != JSON_STRING)
|
||||||
|
{
|
||||||
|
/* Also check for the type */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
membership_str = JsonValueAsString(membership);
|
||||||
|
#define JumpIfMembership(mem, func) do { \
|
||||||
|
if (StrEquals(membership_str, mem)) \
|
||||||
|
{ \
|
||||||
|
return func(room, pdu); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* Step 5.2: If membership is join. */
|
||||||
|
JumpIfMembership("join", AuthorizeJoinMembershipV1);
|
||||||
|
|
||||||
|
/* Step 4.3: Otherwise, allow. */
|
||||||
|
return true;
|
||||||
|
#undef JumpIfMembership
|
||||||
|
}
|
||||||
|
bool
|
||||||
|
AuthoriseEventV1(Room * room, PduV1 pdu)
|
||||||
|
{
|
||||||
|
HashMap *state, *create_event;
|
||||||
|
char *create_event_id;
|
||||||
|
JsonValue *federate;
|
||||||
|
/* Step 1: If m.room.create */
|
||||||
if (StrEquals(pdu.type, "m.room.create"))
|
if (StrEquals(pdu.type, "m.room.create"))
|
||||||
{
|
{
|
||||||
return AuthoriseCreateV1(pdu);
|
return AuthoriseCreateV1(pdu);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Consider, everything else! */
|
/* Step 2: Considering the event's auth_events. */
|
||||||
for (i = 0; i < ArraySize(pdu.auth_events); i++)
|
if (!ConsiderAuthEventsV1(room, pdu))
|
||||||
{
|
{
|
||||||
char *event_id = ArrayGet(pdu.auth_events, i);
|
return false;
|
||||||
/* TODO: Fetch event there */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO */
|
/* Step 3: If the content of the m.room.create event in the room state
|
||||||
|
* has the property m.federate set to false, and the sender domain of
|
||||||
|
* the event does not match the sender domain of the create event,
|
||||||
|
* reject.
|
||||||
|
*/
|
||||||
|
state = RoomStateGet(room);
|
||||||
|
create_event_id = StateGet(state, "m.room.create", "");
|
||||||
|
if (!state || !create_event_id)
|
||||||
|
{
|
||||||
|
/* At this point, [create_event_id] has to exist */
|
||||||
|
StateFree(state); /* create_event_id is also freed. */
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
create_event = RoomEventFetch(room, create_event_id);
|
||||||
|
federate = JsonGet(create_event, 2, "content", "m.federate");
|
||||||
|
if (JsonValueType(federate) == JSON_BOOLEAN)
|
||||||
|
{
|
||||||
|
if (!JsonValueAsBoolean(federate))
|
||||||
|
{
|
||||||
|
char *c_sender =
|
||||||
|
JsonValueAsString(JsonGet(create_event, 1, "sender"));
|
||||||
|
char *p_sender = pdu.sender;
|
||||||
|
if (!VerifyServers(c_sender, p_sender))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 4: If type is m.room.aliases */
|
||||||
|
if (StrEquals(pdu.type, "m.room.aliases"))
|
||||||
|
{
|
||||||
|
return AuthoriseAliasV1(pdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 5: If type is m.room.member */
|
||||||
|
if (StrEquals(pdu.type, "m.room.member"))
|
||||||
|
{
|
||||||
|
return AuthoriseMemberV1(room, pdu);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
static char *
|
static char *
|
||||||
|
@ -357,7 +625,6 @@ RoomEventSendV1(Room * room, HashMap * event)
|
||||||
#undef AddState
|
#undef AddState
|
||||||
}
|
}
|
||||||
/* TODO: Do a size check! */
|
/* TODO: Do a size check! */
|
||||||
finish:
|
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
JsonFree(state);
|
JsonFree(state);
|
||||||
|
@ -373,6 +640,8 @@ static HashMap *
|
||||||
RoomEventSendV3(Room * room, HashMap * event)
|
RoomEventSendV3(Room * room, HashMap * event)
|
||||||
{
|
{
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
(void) room;
|
||||||
|
(void) event;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
HashMap *
|
HashMap *
|
||||||
|
@ -382,7 +651,7 @@ RoomEventSend(Room * room, HashMap * event)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (room->version == 1)
|
if (room->version < 3)
|
||||||
{
|
{
|
||||||
/* Manage with PDUv1 */
|
/* Manage with PDUv1 */
|
||||||
return RoomEventSendV1(room, event);
|
return RoomEventSendV1(room, event);
|
||||||
|
@ -390,3 +659,51 @@ RoomEventSend(Room * room, HashMap * event)
|
||||||
/* Manage with PDUv3 otherwise */
|
/* Manage with PDUv3 otherwise */
|
||||||
return RoomEventSendV3(room, event);
|
return RoomEventSendV3(room, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
CreateSafeID(char *unsafe_id)
|
||||||
|
{
|
||||||
|
size_t length = strlen(unsafe_id);
|
||||||
|
char *safe_id = Malloc(length + 1);
|
||||||
|
size_t i;
|
||||||
|
/* Creates a room ID safe to be put into the database
|
||||||
|
* for room version 3 and above.
|
||||||
|
* (with '/'s replaced by '-') */
|
||||||
|
memcpy(safe_id, unsafe_id, length + 1);
|
||||||
|
for (i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
if (safe_id[i] == '/')
|
||||||
|
{
|
||||||
|
safe_id[i] = '-';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return safe_id;
|
||||||
|
}
|
||||||
|
HashMap *
|
||||||
|
RoomEventFetch(Room *room, char *id)
|
||||||
|
{
|
||||||
|
DbRef *event_ref;
|
||||||
|
HashMap *ret;
|
||||||
|
char *safe_id;
|
||||||
|
|
||||||
|
if (!room || !id)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let's try to locally find that event in our junk. */
|
||||||
|
safe_id = CreateSafeID(id);
|
||||||
|
event_ref = DbLock(room->db, 4, "rooms", room->id, "events", safe_id);
|
||||||
|
if (!event_ref)
|
||||||
|
{
|
||||||
|
/* TODO: Fetch from another homeserver if possible. */
|
||||||
|
ret = NULL;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
ret = JsonDuplicate(DbJson(event_ref));
|
||||||
|
DbUnlock(room->db, event_ref);
|
||||||
|
finish:
|
||||||
|
Free(safe_id);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
36
src/State.c
36
src/State.c
|
@ -26,10 +26,12 @@
|
||||||
#include <State.h>
|
#include <State.h>
|
||||||
|
|
||||||
#include <Cytoplasm/HashMap.h>
|
#include <Cytoplasm/HashMap.h>
|
||||||
|
#include <Cytoplasm/Memory.h>
|
||||||
#include <Cytoplasm/Array.h>
|
#include <Cytoplasm/Array.h>
|
||||||
|
#include <Cytoplasm/Str.h>
|
||||||
|
|
||||||
#include <Room.h>
|
|
||||||
#include <Event.h>
|
#include <Event.h>
|
||||||
|
#include <Room.h>
|
||||||
|
|
||||||
static HashMap *
|
static HashMap *
|
||||||
StateResolveV1(Array * states)
|
StateResolveV1(Array * states)
|
||||||
|
@ -86,3 +88,35 @@ StateResolve(Room * room, HashMap * event)
|
||||||
return StateResolveV2(states);
|
return StateResolveV2(states);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
char *
|
||||||
|
StateGet(HashMap *state, char *type, char *key)
|
||||||
|
{
|
||||||
|
char *full_string;
|
||||||
|
char *ret;
|
||||||
|
if (!state || !type || !key)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
full_string = StrConcat(3, type, ",", key);
|
||||||
|
ret = HashMapGet(state, full_string);
|
||||||
|
Free(full_string);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
StateFree(HashMap *state)
|
||||||
|
{
|
||||||
|
char *full;
|
||||||
|
char *event_id;
|
||||||
|
|
||||||
|
if (!state)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (HashMapIterate(state, &full, (void **) &event_id))
|
||||||
|
{
|
||||||
|
Free(event_id);
|
||||||
|
}
|
||||||
|
HashMapFree(state);
|
||||||
|
}
|
||||||
|
|
|
@ -130,4 +130,12 @@ extern int RoomPrevEventsSet(Room *, Array *);
|
||||||
*/
|
*/
|
||||||
extern HashMap * RoomEventSend(Room *, HashMap *);
|
extern HashMap * RoomEventSend(Room *, HashMap *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a single event's PDU in a room into an
|
||||||
|
* hashmap, given an event ID, from the database
|
||||||
|
* if possible, or otherwise fetched from a remote
|
||||||
|
* homeserver participating in the room.
|
||||||
|
*/
|
||||||
|
extern HashMap * RoomEventFetch(Room *, char *);
|
||||||
|
|
||||||
#endif /* TELODENDRIA_ROOM_H */
|
#endif /* TELODENDRIA_ROOM_H */
|
||||||
|
|
|
@ -54,4 +54,9 @@ extern char *StateSet(HashMap *, char *, char *, char *);
|
||||||
*/
|
*/
|
||||||
extern HashMap * StateResolve(Room *, HashMap *);
|
extern HashMap * StateResolve(Room *, HashMap *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees an entire state table from the heap.
|
||||||
|
*/
|
||||||
|
extern void StateFree(HashMap *);
|
||||||
|
|
||||||
#endif /* TELODENDRIA_STATE_H */
|
#endif /* TELODENDRIA_STATE_H */
|
||||||
|
|
Loading…
Reference in a new issue