diff --git a/src/Room.c b/src/Room.c index 9ce15c6..e1e79d7 100644 --- a/src/Room.c +++ b/src/Room.c @@ -341,6 +341,7 @@ RoomCreate(Db * db, User *user, RoomCreateRequest * req, ServerPart s) JsonSet(json, JsonValueArray(ArrayCreate()), 1, "leaves"); full_creator = ParserRecomposeServerPart(room->creator); JsonSet(json, JsonValueString(full_creator), 1, "creator"); + JsonSet(json, JsonValueInteger(version_num), 1, "version"); Free(full_creator); RoomPopulate(room, user, req, s); @@ -380,6 +381,7 @@ RoomLock(Db * db, char *id) room->state_ref = state_ref; room->leaves_ref = leaves_ref; room->id = StrDuplicate(id); + room->version = JsonValueAsInteger(HashMapGet(DbJson(leaves_ref), "version")); json = DbJson(room->leaves_ref); ParseServerPart( diff --git a/src/Routes.c b/src/Routes.c index 5059df3..bfea0c8 100644 --- a/src/Routes.c +++ b/src/Routes.c @@ -142,6 +142,7 @@ RouterBuild(void) R("/_matrix/client/v3/user/(.*)/filter", RouteFilter); R("/_matrix/client/v3/user/(.*)/filter/(.*)", RouteFilter); + R("/_matrix/client/v3/rooms/(.*)/send/(.*)/(.*)", RouteSendEvent); R("/_matrix/client/v3/createRoom", RouteCreateRoom); diff --git a/src/Routes/RouteSendEvent.c b/src/Routes/RouteSendEvent.c new file mode 100644 index 0000000..e9dbcb2 --- /dev/null +++ b/src/Routes/RouteSendEvent.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with + * other valuable contributors. See CONTRIBUTORS.txt for the full list. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include + + +#include +#include +#include +#include + +#include +#include +#include + +#include + +static char * +GetServerName(Db * db) +{ + char *name; + + Config config; + + ConfigLock(db, &config); + if (!config.ok) + { + return NULL; + } + + name = StrDuplicate(config.serverName); + + ConfigUnlock(&config); + + return name; +} + +ROUTE_IMPL(RouteSendEvent, path, argp) +{ + RouteArgs *args = argp; + Db *db = args->matrixArgs->db; + + HashMap *request = NULL, *event = NULL; + HashMap *response = NULL, *filled = NULL; + + User *user = NULL; + CommonID *id = NULL; + char *token = NULL; + + char *serverName = NULL; + + char *roomId = ArrayGet(path, 0); + char *eventType = ArrayGet(path, 1); + char *transId = ArrayGet(path, 2); + char *sender = NULL; + + Room *room = NULL; + + char *err; + + if (!roomId || !eventType || !transId) + { + /* Should be impossible */ + HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR); + return MatrixErrorCreate(M_UNKNOWN, NULL); + } + if (HttpRequestMethodGet(args->context) != HTTP_PUT) + { + err = "Unknown request method."; + HttpResponseStatus(args->context, HTTP_BAD_REQUEST); + response = MatrixErrorCreate(M_UNRECOGNIZED, err); + goto finish; + } + + serverName = GetServerName(db); + if (!serverName) + { + HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR); + response = MatrixErrorCreate(M_UNKNOWN, NULL); + goto finish; + } + + response = MatrixGetAccessToken(args->context, &token); + if (response) + { + goto finish; + } + + request = JsonDecode(HttpServerStream(args->context)); + if (!request) + { + HttpResponseStatus(args->context, HTTP_BAD_REQUEST); + response = MatrixErrorCreate(M_NOT_JSON, NULL); + goto finish; + } + + user = UserAuthenticate(db, token); + if (!user) + { + HttpResponseStatus(args->context, HTTP_UNAUTHORIZED); + response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL); + goto finish; + } + id = UserIdParse(UserGetName(user), serverName); + id->sigil = '@'; + sender = ParserRecomposeCommonID(*id); + + if ((response = UserGetTransaction(user, transId, "send"))) + { + goto finish; + } + + room = RoomLock(db, roomId); + if (!RoomContainsUser(room, sender)) + { + err = "User is not in the room."; + HttpResponseStatus(args->context, HTTP_UNAUTHORIZED); + response = MatrixErrorCreate(M_FORBIDDEN, err); + goto finish; + } + + event = RoomEventCreate(sender, eventType, NULL, JsonDuplicate(request)); + filled = RoomEventSend(room, event); + JsonFree(event); + + if (!filled) + { + err = "User is not allowed to send event."; + HttpResponseStatus(args->context, HTTP_UNAUTHORIZED); + response = MatrixErrorCreate(M_FORBIDDEN, err); + goto finish; + } + + response = HashMapCreate(); + HashMapSet( + response, "event_id", + JsonValueDuplicate(HashMapGet(filled, "event_id")) + ); + JsonFree(filled); + UserSetTransaction(user, transId, "send", response); +finish: + RoomUnlock(room); + Free(serverName); + if (sender) + { + Free(sender); + } + UserIdFree(id); + UserUnlock(user); + JsonFree(request); + return response; +} diff --git a/src/State.c b/src/State.c index a4134a8..5631e5b 100644 --- a/src/State.c +++ b/src/State.c @@ -240,18 +240,13 @@ StateResolveV2(Array * states) static HashMap * StateFromPrevs(Room *room, Array *states) { - HashMap *ret_state; switch (RoomVersionGet(room)) { case 1: - ret_state = StateResolveV1(room, states); - break; + return StateResolveV1(room, states); default: - ret_state = StateResolveV2(states); - break; + return StateResolveV2(states); } - - return ret_state; } HashMap * @@ -357,9 +352,10 @@ StateCurrent(Room *room) for (i = 0; i < ArraySize(prevEvents); i++) { HashMap *event = - RoomEventFetch(room, JsonValueAsString(ArrayGet(prevEvents, i))); + JsonValueAsObject(ArrayGet(prevEvents, i)); HashMap *state = StateResolve(room, event); + if (HashMapGet(event, "state_key")) { StateSet( diff --git a/src/include/Routes.h b/src/include/Routes.h index 76de377..99332c2 100644 --- a/src/include/Routes.h +++ b/src/include/Routes.h @@ -100,6 +100,7 @@ ROUTE(RouteConfig); ROUTE(RoutePrivileges); ROUTE(RouteCreateRoom); +ROUTE(RouteSendEvent); ROUTE(RouteAliasDirectory); ROUTE(RouteRoomAliases);