forked from Telodendria/Telodendria
Compare commits
No commits in common. "e2d26c7f33190c85b04c320ce8f62c9484203ca6" and "046a04e49553d8bae6f1b89c64c205c1e18c98ac" have entirely different histories.
e2d26c7f33
...
046a04e495
15 changed files with 77 additions and 1102 deletions
|
@ -16,10 +16,6 @@
|
||||||
"fields": {
|
"fields": {
|
||||||
"age": {
|
"age": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
|
||||||
"next_events": {
|
|
||||||
"type": "[string]",
|
|
||||||
"required": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,19 +21,13 @@
|
||||||
},
|
},
|
||||||
"type": "struct"
|
"type": "struct"
|
||||||
},
|
},
|
||||||
"InviteState": {
|
|
||||||
"fields": {
|
|
||||||
"events": { "type": "[StrippedStateEvent]" }
|
|
||||||
},
|
|
||||||
"type": "struct"
|
|
||||||
},
|
|
||||||
"States": {
|
|
||||||
"fields": {
|
|
||||||
"events": { "type": "[StrippedStateEvent]" }
|
|
||||||
},
|
|
||||||
"type": "struct"
|
|
||||||
},
|
|
||||||
"StrippedStateEvent": {
|
"StrippedStateEvent": {
|
||||||
|
"fields": {
|
||||||
|
"events": { "type": "[Event]" }
|
||||||
|
},
|
||||||
|
"type": "struct"
|
||||||
|
},
|
||||||
|
"InviteState": {
|
||||||
"fields": {
|
"fields": {
|
||||||
"content": {
|
"content": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
@ -81,15 +75,14 @@
|
||||||
},
|
},
|
||||||
"JoinedRooms": {
|
"JoinedRooms": {
|
||||||
"fields": {
|
"fields": {
|
||||||
"timeline": { "type": "Timeline" },
|
"timeline": { "type": "Timeline" }
|
||||||
"state": { "type": "States" }
|
|
||||||
},
|
},
|
||||||
"type": "struct"
|
"type": "struct"
|
||||||
},
|
},
|
||||||
"Rooms": {
|
"Rooms": {
|
||||||
"fields": {
|
"fields": {
|
||||||
"invite": { "type": "object" },
|
"invite": { "type": "InvitedRooms" },
|
||||||
"join": { "type": "object" }
|
"join": { "type": "JoinedRooms" }
|
||||||
},
|
},
|
||||||
"type": "struct"
|
"type": "struct"
|
||||||
},
|
},
|
||||||
|
|
27
src/Main.c
27
src/Main.c
|
@ -86,26 +86,6 @@ SignalHandler(int signal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Move this! */
|
|
||||||
static void
|
|
||||||
UsersClean(MatrixHttpHandlerArgs *args)
|
|
||||||
{
|
|
||||||
Db *db = args->db;
|
|
||||||
Array *arr = DbList(db, 1, "users");
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < ArraySize(arr); i++)
|
|
||||||
{
|
|
||||||
char *id = ArrayGet(arr, i);
|
|
||||||
User *user = UserLock(db, id);
|
|
||||||
|
|
||||||
UserCleanTemporaryData(user);
|
|
||||||
UserUnlock(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
DbListFree(arr);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef enum ArgFlag
|
typedef enum ArgFlag
|
||||||
{
|
{
|
||||||
ARG_VERSION = (1 << 0),
|
ARG_VERSION = (1 << 0),
|
||||||
|
@ -167,7 +147,6 @@ start:
|
||||||
token = NULL;
|
token = NULL;
|
||||||
|
|
||||||
memset(&matrixArgs, 0, sizeof(matrixArgs));
|
memset(&matrixArgs, 0, sizeof(matrixArgs));
|
||||||
UserInitialisePushTable();
|
|
||||||
|
|
||||||
if (!LogConfigGlobal())
|
if (!LogConfigGlobal())
|
||||||
{
|
{
|
||||||
|
@ -534,15 +513,10 @@ start:
|
||||||
Log(LOG_DEBUG, "Registering jobs...");
|
Log(LOG_DEBUG, "Registering jobs...");
|
||||||
|
|
||||||
CronEvery(cron, 30 * 60 * 1000, (JobFunc *) UiaCleanup, &matrixArgs);
|
CronEvery(cron, 30 * 60 * 1000, (JobFunc *) UiaCleanup, &matrixArgs);
|
||||||
CronEvery(cron, 5 * 60 * 1000, (JobFunc *) UsersClean, &matrixArgs);
|
|
||||||
|
|
||||||
Log(LOG_NOTICE, "Starting job scheduler...");
|
Log(LOG_NOTICE, "Starting job scheduler...");
|
||||||
CronStart(cron);
|
CronStart(cron);
|
||||||
|
|
||||||
/* We still call it anyways to be sure. */
|
|
||||||
Log(LOG_NOTICE, "Cleaning up user data...");
|
|
||||||
UsersClean(&matrixArgs);
|
|
||||||
|
|
||||||
Log(LOG_NOTICE, "Building routing tree...");
|
Log(LOG_NOTICE, "Building routing tree...");
|
||||||
matrixArgs.router = RouterBuild();
|
matrixArgs.router = RouterBuild();
|
||||||
if (!matrixArgs.router)
|
if (!matrixArgs.router)
|
||||||
|
@ -609,7 +583,6 @@ start:
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
Log(LOG_NOTICE, "Shutting down...");
|
Log(LOG_NOTICE, "Shutting down...");
|
||||||
UserDestroyPushTable();
|
|
||||||
if (httpServers)
|
if (httpServers)
|
||||||
{
|
{
|
||||||
for (i = 0; i < ArraySize(httpServers); i++)
|
for (i = 0; i < ArraySize(httpServers); i++)
|
||||||
|
|
82
src/Room.c
82
src/Room.c
|
@ -52,7 +52,6 @@
|
||||||
|
|
||||||
#define IsState(p, typ, key) (StrEquals(p->type, typ) && \
|
#define IsState(p, typ, key) (StrEquals(p->type, typ) && \
|
||||||
StrEquals(p->state_key, key))
|
StrEquals(p->state_key, key))
|
||||||
|
|
||||||
struct Room
|
struct Room
|
||||||
{
|
{
|
||||||
Db *db;
|
Db *db;
|
||||||
|
@ -1092,25 +1091,22 @@ AuthorizeJoinMembershipV1(Room * room, PduV1 pdu, HashMap *state)
|
||||||
{
|
{
|
||||||
/* Interperet prev properly, as a list of JsonObjects. */
|
/* Interperet prev properly, as a list of JsonObjects. */
|
||||||
char *prev_id = JsonValueAsString(ArrayGet(prev, 0));
|
char *prev_id = JsonValueAsString(ArrayGet(prev, 0));
|
||||||
|
char *ignored;
|
||||||
HashMap *prev_event = RoomEventFetch(room, prev_id);
|
HashMap *prev_event = RoomEventFetch(room, prev_id);
|
||||||
bool flag = false;
|
PduV1 prev_pdu;
|
||||||
|
|
||||||
if (prev_event)
|
if (prev && PduV1FromJson(prev_event, &prev_pdu, &ignored))
|
||||||
{
|
{
|
||||||
char *type = JsonValueAsString(HashMapGet(prev_event, "type"));
|
if (StrEquals(prev_pdu.type, "m.room.create") &&
|
||||||
char *sender = JsonValueAsString(HashMapGet(prev_event, "sender"));
|
StrEquals(prev_pdu.sender, pdu.state_key))
|
||||||
if (StrEquals(type, "m.room.create") &&
|
|
||||||
StrEquals(sender, pdu.state_key))
|
|
||||||
{
|
{
|
||||||
flag = true;
|
PduV1Free(&prev_pdu);
|
||||||
}
|
|
||||||
}
|
|
||||||
JsonFree(prev_event);
|
JsonFree(prev_event);
|
||||||
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
PduV1Free(&prev_pdu);
|
||||||
|
}
|
||||||
|
JsonFree(prev_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step 5.2.2: If the sender does not match state_key, reject. */
|
/* Step 5.2.2: If the sender does not match state_key, reject. */
|
||||||
|
@ -1637,9 +1633,6 @@ RoomEventSendV1(Room * room, HashMap * event)
|
||||||
* errorr status to the user. */
|
* errorr status to the user. */
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
StateFree(state);
|
|
||||||
state = NULL;
|
|
||||||
|
|
||||||
RoomAddEventV1(room, pdu);
|
RoomAddEventV1(room, pdu);
|
||||||
valid = true;
|
valid = true;
|
||||||
|
|
||||||
|
@ -1765,7 +1758,6 @@ RoomAddEventV1(Room *room, PduV1 pdu)
|
||||||
JsonValue *leaves_val;
|
JsonValue *leaves_val;
|
||||||
char *safe_id;
|
char *safe_id;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (!room || room->version >= 3)
|
if (!room || room->version >= 3)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -1820,39 +1812,11 @@ RoomAddEventV1(Room *room, PduV1 pdu)
|
||||||
|
|
||||||
DbUnlock(room->db, event_ref);
|
DbUnlock(room->db, event_ref);
|
||||||
|
|
||||||
for (i = 0; i < ArraySize(prev_events); i++)
|
/* TODO: Store DAG relationships, somehow. */
|
||||||
{
|
|
||||||
JsonValue *event_val = ArrayGet(prev_events, i);
|
|
||||||
char *id = JsonValueAsString(event_val);
|
|
||||||
char *error = NULL;
|
|
||||||
PduV1 prev_pdu = { 0 };
|
|
||||||
HashMap *prev_object = NULL;
|
|
||||||
Array *next_events = NULL;
|
|
||||||
event_ref = DbLock(room->db, 4, "rooms", room->id, "events", id);
|
|
||||||
PduV1FromJson(DbJson(event_ref), &prev_pdu, &error);
|
|
||||||
|
|
||||||
if (!prev_pdu._unsigned.next_events)
|
|
||||||
{
|
|
||||||
prev_pdu._unsigned.next_events = ArrayCreate();
|
|
||||||
}
|
|
||||||
next_events = prev_pdu._unsigned.next_events;
|
|
||||||
|
|
||||||
ArrayAdd(next_events, StrDuplicate(pdu.event_id));
|
|
||||||
|
|
||||||
prev_object = PduV1ToJson(&prev_pdu);
|
|
||||||
DbJsonSet(event_ref, prev_object);
|
|
||||||
|
|
||||||
JsonFree(prev_object);
|
|
||||||
PduV1Free(&prev_pdu);
|
|
||||||
DbUnlock(room->db, event_ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
HashMap *state;
|
|
||||||
char *type, *state_key, *event_id;
|
|
||||||
|
|
||||||
pdu_json = PduV1ToJson(&pdu);
|
pdu_json = PduV1ToJson(&pdu);
|
||||||
|
{
|
||||||
|
CommonID *sid= UserIdParse(pdu.sender, NULL);
|
||||||
|
User *suser = UserLock(room->db, sid->local);
|
||||||
if (StrEquals(pdu.type, "m.room.member"))
|
if (StrEquals(pdu.type, "m.room.member"))
|
||||||
{
|
{
|
||||||
CommonID *id = UserIdParse(pdu.state_key, NULL);
|
CommonID *id = UserIdParse(pdu.state_key, NULL);
|
||||||
|
@ -1881,26 +1845,12 @@ RoomAddEventV1(Room *room, PduV1 pdu)
|
||||||
UserIdFree(id);
|
UserIdFree(id);
|
||||||
UserUnlock(user);
|
UserUnlock(user);
|
||||||
}
|
}
|
||||||
state = StateCurrent(room);
|
|
||||||
while (StateIterate(state, &type, &state_key, (void **) &event_id))
|
|
||||||
{
|
|
||||||
if (StrEquals(type, "m.room.member"))
|
|
||||||
{
|
|
||||||
CommonID *id = UserIdParse(state_key, NULL);
|
|
||||||
User *user = UserLock(room->db, id->local);
|
|
||||||
|
|
||||||
UserPushEvent(user, pdu_json);
|
UserPushEvent(suser, pdu_json);
|
||||||
|
UserIdFree(sid);
|
||||||
UserIdFree(id);
|
UserUnlock(suser);
|
||||||
UserUnlock(user);
|
|
||||||
}
|
}
|
||||||
Free(type);
|
|
||||||
Free(state_key);
|
|
||||||
}
|
|
||||||
StateFree(state);
|
|
||||||
|
|
||||||
JsonFree(pdu_json);
|
JsonFree(pdu_json);
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,10 +77,8 @@ 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/rooms/(.*)/send/(.*)/(.*)", RouteSendEvent);
|
||||||
R("/_matrix/client/v3/rooms/(.*)/state/(.*)/(.*)", RouteSendState);
|
|
||||||
R("/_matrix/client/v3/rooms/(.*)/event/(.*)", RouteFetchEvent);
|
R("/_matrix/client/v3/rooms/(.*)/event/(.*)", RouteFetchEvent);
|
||||||
R("/_matrix/client/v3/rooms/(.*)/join", RouteJoinRoom);
|
R("/_matrix/client/v3/rooms/(.*)/join", RouteJoinRoom);
|
||||||
R("/_matrix/client/v3/rooms/(.*)/messages", RouteMessages);
|
|
||||||
|
|
||||||
R("/_matrix/client/v3/join/(.*)", RouteJoinRoomAlias);
|
R("/_matrix/client/v3/join/(.*)", RouteJoinRoomAlias);
|
||||||
|
|
||||||
|
@ -93,7 +91,6 @@ RouterBuild(void)
|
||||||
R("/_matrix/client/v3/directory/room/(.*)", RouteAliasDirectory);
|
R("/_matrix/client/v3/directory/room/(.*)", RouteAliasDirectory);
|
||||||
R("/_matrix/client/v3/rooms/(.*)/aliases", RouteRoomAliases);
|
R("/_matrix/client/v3/rooms/(.*)/aliases", RouteRoomAliases);
|
||||||
|
|
||||||
|
|
||||||
/* Telodendria Admin API Routes */
|
/* Telodendria Admin API Routes */
|
||||||
|
|
||||||
R("/_telodendria/admin/v1/(restart|shutdown|stats)", RouteProcControl);
|
R("/_telodendria/admin/v1/(restart|shutdown|stats)", RouteProcControl);
|
||||||
|
|
|
@ -104,6 +104,8 @@ ROUTE_IMPL(RouteCreateRoom, path, argp)
|
||||||
JsonFree(request);
|
JsonFree(request);
|
||||||
request = NULL;
|
request = NULL;
|
||||||
|
|
||||||
|
Log(LOG_INFO, "Creating room...");
|
||||||
|
|
||||||
if (!(room = RoomCreate(db, user, &parsed, server)))
|
if (!(room = RoomCreate(db, user, &parsed, server)))
|
||||||
{
|
{
|
||||||
err = "Couldn't create room.";
|
err = "Couldn't create room.";
|
||||||
|
|
|
@ -189,7 +189,7 @@ ROUTE_IMPL(RouteFilter, path, argp)
|
||||||
DbJsonSet(ref, filterJson);
|
DbJsonSet(ref, filterJson);
|
||||||
DbUnlock(db, ref);
|
DbUnlock(db, ref);
|
||||||
|
|
||||||
JsonFree(filterJson);
|
Free(filterJson);
|
||||||
|
|
||||||
response = HashMapCreate();
|
response = HashMapCreate();
|
||||||
HashMapSet(response, "filter_id", JsonValueString(filterId));
|
HashMapSet(response, "filter_id", JsonValueString(filterId));
|
||||||
|
|
|
@ -84,7 +84,6 @@ ROUTE_IMPL(RouteJoinRoomAlias, path, argp)
|
||||||
if (*roomId != '!')
|
if (*roomId != '!')
|
||||||
{
|
{
|
||||||
roomId = RoomResolveAlias(db, roomId);
|
roomId = RoomResolveAlias(db, roomId);
|
||||||
Log(LOG_NOTICE, "Here's my guess: %s", roomId);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -127,7 +126,6 @@ ROUTE_IMPL(RouteJoinRoomAlias, path, argp)
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log(LOG_INFO, "Trying with token %s", token);
|
|
||||||
user = UserAuthenticate(db, token);
|
user = UserAuthenticate(db, token);
|
||||||
if (!user)
|
if (!user)
|
||||||
{
|
{
|
||||||
|
@ -138,11 +136,11 @@ ROUTE_IMPL(RouteJoinRoomAlias, path, argp)
|
||||||
id = UserIdParse(UserGetName(user), serverName);
|
id = UserIdParse(UserGetName(user), serverName);
|
||||||
id->sigil = '@';
|
id->sigil = '@';
|
||||||
sender = ParserRecomposeCommonID(*id);
|
sender = ParserRecomposeCommonID(*id);
|
||||||
Log(LOG_INFO, "Now as %s", sender);
|
|
||||||
|
|
||||||
room = RoomLock(db, roomId);
|
room = RoomLock(db, roomId);
|
||||||
if (!room)
|
if (!room)
|
||||||
{
|
{
|
||||||
|
|
||||||
err = "Room ID does not exist.";
|
err = "Room ID does not exist.";
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_UNKNOWN, err);
|
response = MatrixErrorCreate(M_UNKNOWN, err);
|
||||||
|
@ -151,8 +149,6 @@ ROUTE_IMPL(RouteJoinRoomAlias, path, argp)
|
||||||
if (RoomContainsUser(room, sender))
|
if (RoomContainsUser(room, sender))
|
||||||
{
|
{
|
||||||
err = "User is already in the room.";
|
err = "User is already in the room.";
|
||||||
Log(LOG_INFO, "qhar for %s", sender);
|
|
||||||
|
|
||||||
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
|
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
|
||||||
response = MatrixErrorCreate(M_FORBIDDEN, err);
|
response = MatrixErrorCreate(M_FORBIDDEN, err);
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
|
@ -1,178 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <Routes.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include <Cytoplasm/HashMap.h>
|
|
||||||
#include <Cytoplasm/Memory.h>
|
|
||||||
#include <Cytoplasm/Json.h>
|
|
||||||
#include <Cytoplasm/Str.h>
|
|
||||||
|
|
||||||
#include <User.h>
|
|
||||||
#include <Room.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <Schema/Filter.h>
|
|
||||||
|
|
||||||
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(RouteMessages, path, argp)
|
|
||||||
{
|
|
||||||
RouteArgs *args = argp;
|
|
||||||
Db *db = args->matrixArgs->db;
|
|
||||||
|
|
||||||
HashMap *params = HttpRequestParams(args->context);
|
|
||||||
HashMap *response = NULL;
|
|
||||||
|
|
||||||
User *user = NULL;
|
|
||||||
char *token = NULL;
|
|
||||||
|
|
||||||
char *roomId = ArrayGet(path, 0);
|
|
||||||
char *from = HashMapGet(params, "from");
|
|
||||||
char *limitStr = HashMapGet(params, "limit");
|
|
||||||
char *end = NULL;
|
|
||||||
char *sender = NULL;
|
|
||||||
char *serverName = NULL;
|
|
||||||
CommonID *id = NULL;
|
|
||||||
int limit = strtol(limitStr, NULL, 10);
|
|
||||||
|
|
||||||
Array *messages = NULL;
|
|
||||||
|
|
||||||
Room *room = NULL;
|
|
||||||
|
|
||||||
char *err;
|
|
||||||
|
|
||||||
if (!limit || limit < 0)
|
|
||||||
{
|
|
||||||
limit = 10;
|
|
||||||
}
|
|
||||||
if (!roomId)
|
|
||||||
{
|
|
||||||
/* Should be impossible */
|
|
||||||
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
|
||||||
return MatrixErrorCreate(M_UNKNOWN, NULL);
|
|
||||||
}
|
|
||||||
if (HttpRequestMethodGet(args->context) != HTTP_GET)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
RoomUnlock(room);
|
|
||||||
|
|
||||||
/* TODO: Filters, to, and friends */
|
|
||||||
messages = UserFetchMessages(user, limit, from, &end);
|
|
||||||
if (!messages)
|
|
||||||
{
|
|
||||||
Room *r = RoomLock(db, roomId);
|
|
||||||
Array *leaf = RoomPrevEventsGet(r);
|
|
||||||
HashMap *start = JsonValueAsObject(ArrayGet(leaf, 0));
|
|
||||||
char *startId = StrDuplicate(
|
|
||||||
JsonValueAsString(HashMapGet(start, "event_id"))
|
|
||||||
);
|
|
||||||
char *token = UserNewMessageToken(user, roomId, startId);
|
|
||||||
RoomUnlock(r);
|
|
||||||
|
|
||||||
messages = UserFetchMessages(user, limit, token, &end);
|
|
||||||
Free(token);
|
|
||||||
Free(startId);
|
|
||||||
}
|
|
||||||
response = HashMapCreate();
|
|
||||||
JsonSet(response, JsonValueArray(messages), 1, "chunk");
|
|
||||||
if (end)
|
|
||||||
{
|
|
||||||
JsonSet(response, JsonValueString(end), 1, "end");
|
|
||||||
Free(end);
|
|
||||||
}
|
|
||||||
|
|
||||||
UserFreeMessageToken(user, from);
|
|
||||||
finish:
|
|
||||||
UserUnlock(user);
|
|
||||||
UserIdFree(id);
|
|
||||||
if (sender)
|
|
||||||
{
|
|
||||||
Free(sender);
|
|
||||||
}
|
|
||||||
if (serverName)
|
|
||||||
{
|
|
||||||
Free(serverName);
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}
|
|
|
@ -1,129 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <Cytoplasm/HttpServer.h>
|
|
||||||
#include <Routes.h>
|
|
||||||
|
|
||||||
#include <Cytoplasm/HashMap.h>
|
|
||||||
#include <Cytoplasm/Memory.h>
|
|
||||||
#include <Cytoplasm/Json.h>
|
|
||||||
#include <Cytoplasm/Str.h>
|
|
||||||
|
|
||||||
#include <User.h>
|
|
||||||
#include <Room.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <Schema/Filter.h>
|
|
||||||
|
|
||||||
|
|
||||||
ROUTE_IMPL(RoutePushRules, path, argp)
|
|
||||||
{
|
|
||||||
RouteArgs *args = argp;
|
|
||||||
Db *db = args->matrixArgs->db;
|
|
||||||
|
|
||||||
HashMap *response = NULL;
|
|
||||||
|
|
||||||
User *user = NULL;
|
|
||||||
char *token = NULL;
|
|
||||||
|
|
||||||
char *err;
|
|
||||||
|
|
||||||
if (HttpRequestMethodGet(args->context) != HTTP_GET)
|
|
||||||
{
|
|
||||||
err = "Unknown request method.";
|
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
|
||||||
response = MatrixErrorCreate(M_UNRECOGNIZED, err);
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
response = MatrixGetAccessToken(args->context, &token);
|
|
||||||
if (response)
|
|
||||||
{
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
user = UserAuthenticate(db, token);
|
|
||||||
if (!user)
|
|
||||||
{
|
|
||||||
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
|
|
||||||
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
response = HashMapCreate();
|
|
||||||
JsonSet(response, JsonValueObject(HashMapCreate()), 1, "global");
|
|
||||||
(void) path;
|
|
||||||
finish:
|
|
||||||
UserUnlock(user);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
ROUTE_IMPL(RouteKeyQuery, path, argp)
|
|
||||||
{
|
|
||||||
RouteArgs *args = argp;
|
|
||||||
Db *db = args->matrixArgs->db;
|
|
||||||
|
|
||||||
HashMap *request = NULL;
|
|
||||||
HashMap *response = NULL;
|
|
||||||
|
|
||||||
User *user = NULL;
|
|
||||||
char *token = NULL;
|
|
||||||
|
|
||||||
char *err;
|
|
||||||
|
|
||||||
if (HttpRequestMethodGet(args->context) != HTTP_POST)
|
|
||||||
{
|
|
||||||
err = "Unknown request method.";
|
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
|
||||||
response = MatrixErrorCreate(M_UNRECOGNIZED, err);
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
response = MatrixGetAccessToken(args->context, &token);
|
|
||||||
if (response)
|
|
||||||
{
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
user = UserAuthenticate(db, token);
|
|
||||||
if (!user)
|
|
||||||
{
|
|
||||||
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
|
|
||||||
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
request = JsonDecode(HttpServerStream(args->context));
|
|
||||||
if (!request)
|
|
||||||
{
|
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
|
||||||
response = MatrixErrorCreate(M_NOT_JSON, NULL);
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
response = HashMapCreate();
|
|
||||||
(void) path;
|
|
||||||
finish:
|
|
||||||
JsonFree(request);
|
|
||||||
UserUnlock(user);
|
|
||||||
return response;
|
|
||||||
}
|
|
|
@ -171,120 +171,3 @@ finish:
|
||||||
JsonFree(request);
|
JsonFree(request);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
ROUTE_IMPL(RouteSendState, 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 *stateKey = ArrayGet(path, 2);
|
|
||||||
char *sender = NULL;
|
|
||||||
|
|
||||||
Room *room = NULL;
|
|
||||||
|
|
||||||
char *err;
|
|
||||||
|
|
||||||
if (!roomId || !eventType)
|
|
||||||
{
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log(LOG_INFO, "State event (%s,%s) coming this way", eventType, stateKey);
|
|
||||||
event = RoomEventCreate(
|
|
||||||
sender,
|
|
||||||
eventType, stateKey ? stateKey : "",
|
|
||||||
JsonDuplicate(request)
|
|
||||||
);
|
|
||||||
filled = RoomEventSend(room, event);
|
|
||||||
Log(LOG_INFO, "State event (%s,%s) coming this way", eventType, stateKey);
|
|
||||||
JsonFree(event);
|
|
||||||
Log(LOG_INFO, "And thats freed!");
|
|
||||||
|
|
||||||
if (!filled)
|
|
||||||
{
|
|
||||||
err = "User is not allowed to send state.";
|
|
||||||
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);
|
|
||||||
finish:
|
|
||||||
RoomUnlock(room);
|
|
||||||
Free(serverName);
|
|
||||||
if (sender)
|
|
||||||
{
|
|
||||||
Free(sender);
|
|
||||||
}
|
|
||||||
UserIdFree(id);
|
|
||||||
UserUnlock(user);
|
|
||||||
JsonFree(request);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
|
@ -30,33 +30,14 @@
|
||||||
#include <Cytoplasm/HashMap.h>
|
#include <Cytoplasm/HashMap.h>
|
||||||
#include <Cytoplasm/Memory.h>
|
#include <Cytoplasm/Memory.h>
|
||||||
#include <Cytoplasm/Json.h>
|
#include <Cytoplasm/Json.h>
|
||||||
#include <Cytoplasm/Util.h>
|
|
||||||
#include <Cytoplasm/Str.h>
|
#include <Cytoplasm/Str.h>
|
||||||
|
|
||||||
#include <State.h>
|
|
||||||
#include <User.h>
|
#include <User.h>
|
||||||
#include <Room.h>
|
#include <Room.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
static ClientEventWithoutRoomID
|
#include <Schema/Filter.h>
|
||||||
ClientfyEventSync(HashMap *pdu)
|
|
||||||
{
|
|
||||||
ClientEventWithoutRoomID ret = { 0 };
|
|
||||||
char *ignored;
|
|
||||||
ClientEventWithoutRoomIDFromJson(pdu, &ret, &ignored);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
static StrippedStateEvent
|
|
||||||
StripStateEventSync(HashMap *pdu)
|
|
||||||
{
|
|
||||||
StrippedStateEvent ret = { 0 };
|
|
||||||
char *ignored;
|
|
||||||
StrippedStateEventFromJson(pdu, &ret, &ignored);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ROUTE_IMPL(RouteSync, path, argp)
|
ROUTE_IMPL(RouteSync, path, argp)
|
||||||
{
|
{
|
||||||
|
@ -65,27 +46,18 @@ ROUTE_IMPL(RouteSync, path, argp)
|
||||||
|
|
||||||
HashMap *params = NULL;
|
HashMap *params = NULL;
|
||||||
HashMap *response = NULL;
|
HashMap *response = NULL;
|
||||||
SyncResponse sync = { 0 };
|
|
||||||
|
|
||||||
Array *invites;
|
|
||||||
Array *joins;
|
HashMap *rooms = NULL;
|
||||||
size_t i;
|
|
||||||
|
|
||||||
User *user = NULL;
|
User *user = NULL;
|
||||||
char *token = NULL;
|
char *token = NULL;
|
||||||
char *prevBatch = NULL;
|
char *prevBatch = NULL;
|
||||||
char *nextBatch = NULL;
|
char *nextBatch = NULL;
|
||||||
char *currBatch = NULL;
|
char *currBatch = NULL;
|
||||||
char *timeout = NULL;
|
|
||||||
|
|
||||||
char *err;
|
char *err;
|
||||||
|
|
||||||
int timeoutDuration;
|
|
||||||
|
|
||||||
/* TODO: Respect `timeout', (and stop when something is
|
|
||||||
* pushed, maybe by 'polling' the database? sounds like
|
|
||||||
* a bad idea) */
|
|
||||||
|
|
||||||
if (HttpRequestMethodGet(args->context) != HTTP_GET)
|
if (HttpRequestMethodGet(args->context) != HTTP_GET)
|
||||||
{
|
{
|
||||||
err = "Unknown request method.";
|
err = "Unknown request method.";
|
||||||
|
@ -107,142 +79,70 @@ ROUTE_IMPL(RouteSync, path, argp)
|
||||||
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
|
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
params = HttpRequestParams(args->context);
|
params = HttpRequestParams(args->context);
|
||||||
prevBatch = HashMapGet(params, "since");
|
prevBatch = HashMapGet(params, "since");
|
||||||
timeout = HashMapGet(params, "timeout");
|
|
||||||
timeoutDuration = atoi(timeout);
|
|
||||||
|
|
||||||
|
|
||||||
if (!prevBatch)
|
if (!prevBatch)
|
||||||
{
|
{
|
||||||
prevBatch = NULL;
|
|
||||||
nextBatch = UserInitSyncDiff(user);
|
nextBatch = UserInitSyncDiff(user);
|
||||||
UserFillSyncDiff(user, nextBatch);
|
UserFillSyncDiff(user, nextBatch);
|
||||||
}
|
}
|
||||||
else if (timeout && timeoutDuration)
|
|
||||||
{
|
|
||||||
char *name = StrDuplicate(UserGetName(user));
|
|
||||||
int passed = 0;
|
|
||||||
|
|
||||||
UserUnlock(user);
|
|
||||||
|
|
||||||
/* TODO: Unlocking the user for other threads to notify us is not
|
|
||||||
* wise.
|
|
||||||
* Also, Telodendria will NOT reply to ^C while someone is executing
|
|
||||||
* a sync. */
|
|
||||||
while (passed < timeoutDuration)
|
|
||||||
{
|
|
||||||
if (UserGetNotification(name))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
UtilSleepMillis(100);
|
|
||||||
passed += 100;
|
|
||||||
}
|
|
||||||
Free(name);
|
|
||||||
user = UserAuthenticate(db, token);
|
|
||||||
}
|
|
||||||
currBatch = prevBatch ? prevBatch : nextBatch;
|
currBatch = prevBatch ? prevBatch : nextBatch;
|
||||||
|
|
||||||
/* TODO: I only am manually parsing this because j2s does not support
|
/* TODO: I only am manually parsing this because j2s does not support
|
||||||
* a hashmap of unknown keys pointing to a known type. */
|
* a hashmap of unknown keys pointing to a known type. */
|
||||||
sync.rooms.invite = HashMapCreate();
|
response = HashMapCreate();
|
||||||
sync.rooms.join = HashMapCreate();
|
rooms = HashMapCreate();
|
||||||
|
|
||||||
/* invites */
|
/* invites */
|
||||||
|
{
|
||||||
|
Array *invites;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
invites = UserGetInvites(user, currBatch);
|
invites = UserGetInvites(user, currBatch);
|
||||||
for (i = 0; i < ArraySize(invites); i++)
|
for (i = 0; i < ArraySize(invites); i++)
|
||||||
{
|
{
|
||||||
char *roomId = ArrayGet(invites, i);
|
char *roomId = ArrayGet(invites, i);
|
||||||
InvitedRooms invited = { 0 };
|
|
||||||
HashMap *invitedObject;
|
|
||||||
|
|
||||||
invited.invite_state.events = ArrayCreate();
|
|
||||||
invitedObject = InvitedRoomsToJson(&invited);
|
|
||||||
JsonSet(
|
JsonSet(
|
||||||
sync.rooms.invite,
|
rooms,
|
||||||
JsonValueObject(invitedObject),
|
JsonValueObject(HashMapCreate()),
|
||||||
1, roomId
|
2, "invites", roomId
|
||||||
);
|
);
|
||||||
InvitedRoomsFree(&invited);
|
|
||||||
}
|
}
|
||||||
UserFreeList(invites);
|
UserFreeList(invites);
|
||||||
|
}
|
||||||
|
|
||||||
/* Joins */
|
/* Joins */
|
||||||
|
{
|
||||||
|
Array *joins;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
joins = UserGetJoins(user, currBatch);
|
joins = UserGetJoins(user, currBatch);
|
||||||
for (i = 0; i < ArraySize(joins); i++)
|
for (i = 0; i < ArraySize(joins); i++)
|
||||||
{
|
{
|
||||||
char *roomId = ArrayGet(joins, i);
|
char *roomId = ArrayGet(joins, i);
|
||||||
Array *el = UserGetEvents(user, currBatch, roomId);
|
HashMap *room = HashMapCreate();
|
||||||
size_t j;
|
|
||||||
Room *r = RoomLock(db, roomId);
|
|
||||||
HashMap *state = StateCurrent(r);
|
|
||||||
char *firstEvent = NULL;
|
|
||||||
JoinedRooms joined = { 0 };
|
|
||||||
HashMap *joinedObj;
|
|
||||||
char *type, *key, *id;
|
|
||||||
|
|
||||||
joined.timeline.events = ArrayCreate();
|
/* TODO: Add history. */
|
||||||
|
|
||||||
for (j = 0; j < ArraySize(el); j++)
|
JsonSet(
|
||||||
{
|
rooms,
|
||||||
char *event = ArrayGet(el, j);
|
JsonValueObject(room),
|
||||||
HashMap *e = RoomEventFetch(r, event);
|
2, "join", roomId
|
||||||
ClientEventWithoutRoomID rc = ClientfyEventSync(e);
|
|
||||||
ClientEventWithoutRoomID *c = Malloc(sizeof(*c));
|
|
||||||
memcpy(c, &rc, sizeof(*c));
|
|
||||||
|
|
||||||
JsonFree(e);
|
|
||||||
|
|
||||||
if (j == 0)
|
|
||||||
{
|
|
||||||
firstEvent = c->event_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayAdd(joined.timeline.events, c);
|
|
||||||
}
|
|
||||||
joined.timeline.prev_batch = UserNewMessageToken(
|
|
||||||
user, roomId, firstEvent
|
|
||||||
);
|
);
|
||||||
/* TODO: Don't shove the entire state.
|
|
||||||
* That's a recipe for disaster, especially on large rooms. */
|
|
||||||
joined.state.events = ArrayCreate();
|
|
||||||
while (StateIterate(state, &type, &key, (void **) &id))
|
|
||||||
{
|
|
||||||
HashMap *e = RoomEventFetch(r, id);
|
|
||||||
StrippedStateEvent rs = StripStateEventSync(e);
|
|
||||||
StrippedStateEvent *s = Malloc(sizeof(*s));
|
|
||||||
memcpy(s, &rs, sizeof(*s));
|
|
||||||
|
|
||||||
JsonFree(e);
|
|
||||||
|
|
||||||
ArrayAdd(joined.state.events, s);
|
|
||||||
Free(type);
|
|
||||||
Free(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
StateFree(state);
|
|
||||||
RoomUnlock(r);
|
|
||||||
UserFreeList(el);
|
|
||||||
|
|
||||||
joinedObj = JoinedRoomsToJson(&joined);
|
|
||||||
HashMapSet(sync.rooms.join, roomId, JsonValueObject(joinedObj));
|
|
||||||
JoinedRoomsFree(&joined);
|
|
||||||
}
|
}
|
||||||
UserFreeList(joins);
|
UserFreeList(joins);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) path;
|
||||||
if (prevBatch)
|
if (prevBatch)
|
||||||
{
|
{
|
||||||
UserDropSync(user, prevBatch);
|
UserDropSync(user, prevBatch);
|
||||||
nextBatch = UserInitSyncDiff(user);
|
nextBatch = UserInitSyncDiff(user);
|
||||||
UserFillSyncDiff(user, nextBatch);
|
|
||||||
}
|
}
|
||||||
sync.next_batch = nextBatch;
|
HashMapSet(response, "next_batch", JsonValueString(nextBatch));
|
||||||
response = SyncResponseToJson(&sync);
|
Free(nextBatch);
|
||||||
SyncResponseFree(&sync);
|
HashMapSet(response, "rooms", JsonValueObject(rooms));
|
||||||
finish:
|
finish:
|
||||||
UserUnlock(user);
|
UserUnlock(user);
|
||||||
(void) path;
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
344
src/User.c
344
src/User.c
|
@ -32,10 +32,8 @@
|
||||||
#include <Cytoplasm/Log.h>
|
#include <Cytoplasm/Log.h>
|
||||||
|
|
||||||
#include <Parser.h>
|
#include <Parser.h>
|
||||||
#include <Room.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
struct User
|
struct User
|
||||||
{
|
{
|
||||||
|
@ -46,9 +44,6 @@ struct User
|
||||||
char *deviceId;
|
char *deviceId;
|
||||||
};
|
};
|
||||||
|
|
||||||
static pthread_mutex_t pushLock;
|
|
||||||
static HashMap *pushTable = NULL;
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
UserValidate(char *localpart, char *domain)
|
UserValidate(char *localpart, char *domain)
|
||||||
{
|
{
|
||||||
|
@ -115,7 +110,7 @@ UserLock(Db * db, char *name)
|
||||||
User *user = NULL;
|
User *user = NULL;
|
||||||
DbRef *ref = NULL;
|
DbRef *ref = NULL;
|
||||||
|
|
||||||
if (!name || !UserExists(db, name))
|
if (!UserExists(db, name))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -179,22 +174,16 @@ bool
|
||||||
UserUnlock(User * user)
|
UserUnlock(User * user)
|
||||||
{
|
{
|
||||||
bool ret;
|
bool ret;
|
||||||
Db *db;
|
|
||||||
DbRef *ref;
|
|
||||||
|
|
||||||
if (!user)
|
if (!user)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
db = user->db;
|
|
||||||
ref = user->ref;
|
|
||||||
|
|
||||||
Free(user->name);
|
Free(user->name);
|
||||||
Free(user->deviceId);
|
Free(user->deviceId);
|
||||||
|
|
||||||
ret = DbUnlock(db, ref);
|
ret = DbUnlock(user->db, user->ref);
|
||||||
user->db = NULL;
|
|
||||||
user->ref = NULL;
|
|
||||||
Free(user);
|
Free(user);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1068,11 +1057,7 @@ UserAddJoin(User *user, char *roomId)
|
||||||
data = DbJson(user->ref);
|
data = DbJson(user->ref);
|
||||||
joins = JsonValueAsObject(HashMapGet(data, "joins"));
|
joins = JsonValueAsObject(HashMapGet(data, "joins"));
|
||||||
|
|
||||||
if (!HashMapGet(joins, roomId))
|
|
||||||
{
|
|
||||||
JsonFree(HashMapSet(joins, roomId, JsonValueNull()));
|
JsonFree(HashMapSet(joins, roomId, JsonValueNull()));
|
||||||
}
|
|
||||||
UserNotifyUser(user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1089,7 +1074,6 @@ UserRemoveJoin(User *user, char *roomId)
|
||||||
joins = JsonValueAsObject(HashMapGet(data, "joins"));
|
joins = JsonValueAsObject(HashMapGet(data, "joins"));
|
||||||
|
|
||||||
JsonFree(HashMapDelete(joins, roomId));
|
JsonFree(HashMapDelete(joins, roomId));
|
||||||
UserNotifyUser(user);
|
|
||||||
}
|
}
|
||||||
Array *
|
Array *
|
||||||
UserListJoins(User *user)
|
UserListJoins(User *user)
|
||||||
|
@ -1158,8 +1142,6 @@ UserInitSyncDiff(User *user)
|
||||||
HashMapSet(data, "leaves", JsonValueArray(ArrayCreate()));
|
HashMapSet(data, "leaves", JsonValueArray(ArrayCreate()));
|
||||||
HashMapSet(data, "joins", JsonValueObject(HashMapCreate()));
|
HashMapSet(data, "joins", JsonValueObject(HashMapCreate()));
|
||||||
|
|
||||||
HashMapSet(data, "creation", JsonValueInteger(UtilTsMillis()));
|
|
||||||
|
|
||||||
DbUnlock(user->db, syncRef);
|
DbUnlock(user->db, syncRef);
|
||||||
|
|
||||||
return nextBatch;
|
return nextBatch;
|
||||||
|
@ -1191,7 +1173,6 @@ UserPushInviteSync(User *user, char *roomId)
|
||||||
DbUnlock(user->db, syncRef);
|
DbUnlock(user->db, syncRef);
|
||||||
}
|
}
|
||||||
DbListFree(entries);
|
DbListFree(entries);
|
||||||
UserNotifyUser(user);
|
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
UserPushJoinSync(User *user, char *roomId)
|
UserPushJoinSync(User *user, char *roomId)
|
||||||
|
@ -1231,7 +1212,6 @@ UserPushJoinSync(User *user, char *roomId)
|
||||||
DbUnlock(user->db, syncRef);
|
DbUnlock(user->db, syncRef);
|
||||||
}
|
}
|
||||||
DbListFree(entries);
|
DbListFree(entries);
|
||||||
UserNotifyUser(user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1271,8 +1251,6 @@ UserPushEvent(User *user, HashMap *event)
|
||||||
DbUnlock(user->db, syncRef);
|
DbUnlock(user->db, syncRef);
|
||||||
}
|
}
|
||||||
DbListFree(entries);
|
DbListFree(entries);
|
||||||
|
|
||||||
UserNotifyUser(user);
|
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
UserDropSync(User *user, char *batch)
|
UserDropSync(User *user, char *batch)
|
||||||
|
@ -1335,21 +1313,9 @@ UserFillSyncDiff(User *user, char *batch)
|
||||||
HashMap *joinEntry;
|
HashMap *joinEntry;
|
||||||
HashMap *data = DbJson(syncRef);
|
HashMap *data = DbJson(syncRef);
|
||||||
HashMap *join = JsonValueAsObject(HashMapGet(data, "joins"));
|
HashMap *join = JsonValueAsObject(HashMapGet(data, "joins"));
|
||||||
Array *timeline = ArrayCreate();
|
|
||||||
Room *r = RoomLock(user->db, roomId);
|
|
||||||
Array *prevs = RoomPrevEventsGet(r);
|
|
||||||
size_t j;
|
|
||||||
|
|
||||||
for (j = 0; j < ArraySize(prevs); j++)
|
|
||||||
{
|
|
||||||
HashMap *e = JsonValueAsObject(ArrayGet(prevs, j));
|
|
||||||
/* TODO: Backfill the user a 'lil more. */
|
|
||||||
ArrayAdd(timeline, JsonValueDuplicate(HashMapGet(e, "event_id")));
|
|
||||||
}
|
|
||||||
RoomUnlock(r);
|
|
||||||
|
|
||||||
joinEntry = HashMapCreate();
|
joinEntry = HashMapCreate();
|
||||||
HashMapSet(joinEntry, "timeline", JsonValueArray(timeline));
|
HashMapSet(joinEntry, "timeline", JsonValueArray(ArrayCreate()));
|
||||||
|
|
||||||
if (!HashMapGet(join, roomId))
|
if (!HashMapGet(join, roomId))
|
||||||
{
|
{
|
||||||
|
@ -1366,7 +1332,6 @@ UserFillSyncDiff(User *user, char *batch)
|
||||||
Array *
|
Array *
|
||||||
UserGetJoins(User *user, char *batch)
|
UserGetJoins(User *user, char *batch)
|
||||||
{
|
{
|
||||||
Db *db;
|
|
||||||
DbRef *syncRef;
|
DbRef *syncRef;
|
||||||
HashMap *data;
|
HashMap *data;
|
||||||
Array *keys;
|
Array *keys;
|
||||||
|
@ -1376,8 +1341,7 @@ UserGetJoins(User *user, char *batch)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
db = user->db;
|
syncRef = DbLock(user->db, 4, "users", user->name, "sync", batch);
|
||||||
syncRef = DbLock(db, 4, "users", user->name, "sync", batch);
|
|
||||||
if (!syncRef)
|
if (!syncRef)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1392,305 +1356,7 @@ UserGetJoins(User *user, char *batch)
|
||||||
ArraySet(keys, i, StrDuplicate(str));
|
ArraySet(keys, i, StrDuplicate(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
DbUnlock(db, syncRef);
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
Array *
|
|
||||||
UserGetEvents(User *user, char *batch, char *roomId)
|
|
||||||
{
|
|
||||||
DbRef *syncRef;
|
|
||||||
HashMap *data;
|
|
||||||
HashMap *joins;
|
|
||||||
Array *keys, *ret;
|
|
||||||
size_t i;
|
|
||||||
if (!user || !batch || !roomId)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
syncRef = DbLock(user->db, 4, "users", user->name, "sync", batch);
|
|
||||||
if (!syncRef)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = DbJson(syncRef);
|
|
||||||
|
|
||||||
joins = JsonValueAsObject(JsonGet(data, 2, "joins", roomId));
|
|
||||||
|
|
||||||
keys = (JsonValueAsArray(HashMapGet(joins, "timeline")));
|
|
||||||
ret = ArrayCreate();
|
|
||||||
for (i = 0; i < ArraySize(keys); i++)
|
|
||||||
{
|
|
||||||
char *str = JsonValueAsString(ArrayGet(keys, i));
|
|
||||||
|
|
||||||
ArrayAdd(ret, StrDuplicate(str));
|
|
||||||
}
|
|
||||||
|
|
||||||
DbUnlock(user->db, syncRef);
|
DbUnlock(user->db, syncRef);
|
||||||
return ret;
|
return keys;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char *
|
|
||||||
UserNewMessageToken(User *user, char *room, char *event)
|
|
||||||
{
|
|
||||||
DbRef *messageRef;
|
|
||||||
HashMap *json;
|
|
||||||
char *messageToken;
|
|
||||||
if (!user || !room || !event)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
messageToken = StrRandom(16);
|
|
||||||
messageRef = DbCreate(user->db,
|
|
||||||
4, "users", user->name, "msg", messageToken
|
|
||||||
);
|
|
||||||
json = DbJson(messageRef);
|
|
||||||
|
|
||||||
HashMapSet(json, "room", JsonValueString(room));
|
|
||||||
HashMapSet(json, "from", JsonValueString(event));
|
|
||||||
|
|
||||||
DbUnlock(user->db, messageRef);
|
|
||||||
return messageToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
Array *
|
|
||||||
UserFetchMessages(User *user, int n, char *token, char **next)
|
|
||||||
{
|
|
||||||
Array *messages = NULL;
|
|
||||||
Array *nexts = NULL;
|
|
||||||
DbRef *messageRef;
|
|
||||||
HashMap *json;
|
|
||||||
Room *room;
|
|
||||||
char *roomId;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
bool limited = false;
|
|
||||||
bool dir = false;
|
|
||||||
|
|
||||||
if (!user || !token || n == 0)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n < 0)
|
|
||||||
{
|
|
||||||
n = -n;
|
|
||||||
dir = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
messageRef = DbLock(user->db,
|
|
||||||
4, "users", user->name, "msg", token
|
|
||||||
);
|
|
||||||
json = DbJson(messageRef);
|
|
||||||
if (!messageRef)
|
|
||||||
{
|
|
||||||
/* Regenerate a new one */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
roomId = JsonValueAsString(HashMapGet(json, "room"));
|
|
||||||
room = RoomLock(user->db, roomId);
|
|
||||||
|
|
||||||
/* TODO (very important): CHECK IF THE USER IS ABLE TO SEE
|
|
||||||
* HISTORY. THROUGHOUT THE STEPS HERE. */
|
|
||||||
if (!room)
|
|
||||||
{
|
|
||||||
DbUnlock(user->db, messageRef);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
nexts = ArrayCreate();
|
|
||||||
messages = ArrayCreate();
|
|
||||||
|
|
||||||
/* A stack of elements to deal with the DAG. */
|
|
||||||
ArrayAdd(nexts,
|
|
||||||
StrDuplicate(JsonValueAsString(HashMapGet(json, "from")))
|
|
||||||
);
|
|
||||||
for (i = 0; i < (size_t) n && ArraySize(nexts); i++)
|
|
||||||
{
|
|
||||||
char *curr = ArrayDelete(nexts, ArraySize(nexts) - 1);
|
|
||||||
HashMap *event = RoomEventFetch(room, curr);
|
|
||||||
Array *prevEvents;
|
|
||||||
size_t j;
|
|
||||||
|
|
||||||
Free(curr);
|
|
||||||
|
|
||||||
/* Push event into our message list. */
|
|
||||||
ArrayAdd(messages, event);
|
|
||||||
|
|
||||||
prevEvents = JsonValueAsArray(HashMapGet(event, "prev_events"));
|
|
||||||
if (dir)
|
|
||||||
{
|
|
||||||
HashMap *unsign = JsonValueAsObject(HashMapGet(event, "unsigned"));
|
|
||||||
|
|
||||||
/* prevEvents is now nextEvents */
|
|
||||||
prevEvents = JsonValueAsArray(HashMapGet(unsign, "next_events"));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (j = 0; j < ArraySize(prevEvents); j++)
|
|
||||||
{
|
|
||||||
char *prevEvent = JsonValueAsString(ArrayGet(prevEvents, j));
|
|
||||||
|
|
||||||
ArrayAdd(nexts, StrDuplicate(prevEvent));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ArraySize(prevEvents) == 0)
|
|
||||||
{
|
|
||||||
limited = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i = 0; i < ArraySize(nexts); i++)
|
|
||||||
{
|
|
||||||
Free(ArrayGet(nexts, i));
|
|
||||||
}
|
|
||||||
ArrayFree(nexts);
|
|
||||||
RoomUnlock(room);
|
|
||||||
|
|
||||||
if (next && !limited)
|
|
||||||
{
|
|
||||||
HashMap *lastMessage = ArrayGet(messages, ArraySize(messages) - 1);
|
|
||||||
char *eId = JsonValueAsString(HashMapGet(lastMessage, "event_id"));
|
|
||||||
|
|
||||||
*next = UserNewMessageToken(user, roomId, eId);
|
|
||||||
}
|
|
||||||
|
|
||||||
DbUnlock(user->db, messageRef);
|
|
||||||
for (i = 0; i < ArraySize(messages); i++)
|
|
||||||
{
|
|
||||||
HashMap *e = ArrayGet(messages, i);
|
|
||||||
ArraySet(messages, i, JsonValueObject(e));
|
|
||||||
}
|
|
||||||
return messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
UserFreeMessageToken(User *user, char *token)
|
|
||||||
{
|
|
||||||
if (!user || !token)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DbDelete(user->db,
|
|
||||||
4, "users", user->name, "msg", token
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void
|
|
||||||
UserCleanTemporaryData(User *user)
|
|
||||||
{
|
|
||||||
Array *list;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if (!user)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
list = DbList(user->db, 3, "users", user->name, "msg");
|
|
||||||
for (i = 0; i < ArraySize(list); i++)
|
|
||||||
{
|
|
||||||
char *token = ArrayGet(list, i);
|
|
||||||
UserFreeMessageToken(user, token);
|
|
||||||
}
|
|
||||||
DbListFree(list);
|
|
||||||
|
|
||||||
list = DbList(user->db, 3, "users", user->name, "sync");
|
|
||||||
for (i = 0; i < ArraySize(list); i++)
|
|
||||||
{
|
|
||||||
char *token = ArrayGet(list, i);
|
|
||||||
if (UserIsSyncOld(user, token))
|
|
||||||
{
|
|
||||||
UserDropSync(user, token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DbListFree(list);
|
|
||||||
}
|
|
||||||
bool
|
|
||||||
UserIsSyncOld(User *user, char *token)
|
|
||||||
{
|
|
||||||
DbRef *ref;
|
|
||||||
HashMap *map;
|
|
||||||
int64_t dt;
|
|
||||||
|
|
||||||
if (!user || !token)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ref = DbLock(user->db, 4, "users", user->name, "sync", token);
|
|
||||||
map = DbJson(ref);
|
|
||||||
|
|
||||||
dt = UtilTsMillis() - JsonValueAsInteger(HashMapGet(map, "creation"));
|
|
||||||
|
|
||||||
DbUnlock(user->db, ref);
|
|
||||||
return dt > (5 * 60 * 1000); /* 5-minutes of timeout. */
|
|
||||||
}
|
|
||||||
bool
|
|
||||||
UserSyncExists(User *user, char *sync)
|
|
||||||
{
|
|
||||||
if (!user || !sync)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return DbLock(user->db, 4, "users", user->name, "sync", sync);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extern void
|
|
||||||
UserInitialisePushTable(void)
|
|
||||||
{
|
|
||||||
if (pushTable)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pthread_mutex_init(&pushLock, NULL);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&pushLock);
|
|
||||||
pushTable = HashMapCreate();
|
|
||||||
pthread_mutex_unlock(&pushLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
UserNotifyUser(User *user)
|
|
||||||
{
|
|
||||||
if (!user || !pushTable)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pthread_mutex_lock(&pushLock);
|
|
||||||
HashMapSet(pushTable, user->name, user->name);
|
|
||||||
pthread_mutex_unlock(&pushLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
UserGetNotification(char *user)
|
|
||||||
{
|
|
||||||
bool ret;
|
|
||||||
if (!user || !pushTable)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
pthread_mutex_lock(&pushLock);
|
|
||||||
ret = !!HashMapGet(pushTable, user);
|
|
||||||
HashMapDelete(pushTable, user);
|
|
||||||
pthread_mutex_unlock(&pushLock);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
UserDestroyPushTable(void)
|
|
||||||
{
|
|
||||||
if (!pushTable)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_lock(&pushLock);
|
|
||||||
HashMapFree(pushTable);
|
|
||||||
pushTable = NULL;
|
|
||||||
pthread_mutex_unlock(&pushLock);
|
|
||||||
pthread_mutex_destroy(&pushLock);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,14 +100,12 @@ ROUTE(RouteConfig);
|
||||||
ROUTE(RoutePrivileges);
|
ROUTE(RoutePrivileges);
|
||||||
|
|
||||||
ROUTE(RouteCreateRoom);
|
ROUTE(RouteCreateRoom);
|
||||||
ROUTE(RouteSendEvent);
|
|
||||||
ROUTE(RouteSendState);
|
|
||||||
ROUTE(RouteJoinRoom);
|
|
||||||
ROUTE(RouteJoinRoomAlias);
|
|
||||||
ROUTE(RouteFetchEvent);
|
ROUTE(RouteFetchEvent);
|
||||||
|
ROUTE(RouteSendEvent);
|
||||||
|
ROUTE(RouteJoinRoom);
|
||||||
ROUTE(RouteJoinedRooms);
|
ROUTE(RouteJoinedRooms);
|
||||||
|
ROUTE(RouteJoinRoomAlias);
|
||||||
ROUTE(RouteSync);
|
ROUTE(RouteSync);
|
||||||
ROUTE(RouteMessages);
|
|
||||||
|
|
||||||
ROUTE(RouteAliasDirectory);
|
ROUTE(RouteAliasDirectory);
|
||||||
ROUTE(RouteRoomAliases);
|
ROUTE(RouteRoomAliases);
|
||||||
|
@ -115,6 +113,7 @@ ROUTE(RouteRoomAliases);
|
||||||
ROUTE(RouteAdminDeactivate);
|
ROUTE(RouteAdminDeactivate);
|
||||||
|
|
||||||
ROUTE(RouteAdminTokens);
|
ROUTE(RouteAdminTokens);
|
||||||
|
|
||||||
#undef ROUTE
|
#undef ROUTE
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -91,7 +91,6 @@ typedef struct UserLoginInfo
|
||||||
char *refreshToken;
|
char *refreshToken;
|
||||||
} UserLoginInfo;
|
} UserLoginInfo;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take a localpart and domain as separate parameters and validate them
|
* Take a localpart and domain as separate parameters and validate them
|
||||||
* against the rules of the Matrix specification. The reasion the
|
* against the rules of the Matrix specification. The reasion the
|
||||||
|
@ -404,81 +403,9 @@ extern Array * UserGetInvites(User *, char *);
|
||||||
*/
|
*/
|
||||||
extern Array * UserGetJoins(User *, char *);
|
extern Array * UserGetJoins(User *, char *);
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of event IDs for a diff table(and room ID),
|
|
||||||
* to be freed by
|
|
||||||
* .Fn UserFreeList .
|
|
||||||
*/
|
|
||||||
extern Array * UserGetEvents(User *, char *, char *);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Drops a sync diff, denoted by it's previous batch ID, if it
|
* Drops a sync diff, denoted by it's previous batch ID, if it
|
||||||
* exists.
|
* exists.
|
||||||
*/
|
*/
|
||||||
extern void UserDropSync(User *, char *);
|
extern void UserDropSync(User *, char *);
|
||||||
|
|
||||||
/**
|
|
||||||
* Verifies if the 'sync' data is considered old, and can be
|
|
||||||
* reasonably removed from the database.
|
|
||||||
*/
|
|
||||||
extern bool UserIsSyncOld(User *, char *);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verifies if a sync diff exists.
|
|
||||||
*/
|
|
||||||
extern bool UserSyncExists(User *, char *);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new "message token" start from a room and event ID,
|
|
||||||
* given a specified direction(with false<=>'b' and true<=>'f')
|
|
||||||
* to be used by /messages.
|
|
||||||
*/
|
|
||||||
extern char * UserNewMessageToken(User *, char *, char *);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Grabs events from a message token(with the correct direction)
|
|
||||||
* into an array of HashMaps(which store PDU objects).
|
|
||||||
* If the string pointer is not NULL, this function sets its
|
|
||||||
* value to a new message token(which is stored on the heap),
|
|
||||||
* if and only if, there are any new events to retrieve.
|
|
||||||
*
|
|
||||||
* If the counter is negative, then it is treated as a 'f',
|
|
||||||
* otherwise, it is treated as 'b'.
|
|
||||||
*/
|
|
||||||
extern Array * UserFetchMessages(User *, int, char *, char **);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes a "message token".
|
|
||||||
*/
|
|
||||||
extern void UserFreeMessageToken(User *, char *);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes temporary data about a specific user.
|
|
||||||
*/
|
|
||||||
extern void UserCleanTemporaryData(User *);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise a temporary sync table to signal any /sync changes.
|
|
||||||
* This should be paired with a call to
|
|
||||||
* .Fn UserDestroyPushTable .
|
|
||||||
*/
|
|
||||||
extern void UserInitialisePushTable(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notifies the user of a sync update.
|
|
||||||
*/
|
|
||||||
extern void UserNotifyUser(User *);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verifies if the user has been notified, and if it is, then
|
|
||||||
* removes the notification
|
|
||||||
*/
|
|
||||||
extern bool UserGetNotification(char *);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroys the temporary push table created by
|
|
||||||
* .Fn UserInitialisePushTable .
|
|
||||||
*/
|
|
||||||
extern void UserDestroyPushTable(void);
|
|
||||||
#endif /* TELODENDRIA_USER_H */
|
#endif /* TELODENDRIA_USER_H */
|
||||||
|
|
Loading…
Reference in a new issue