diff --git a/src/Room.c b/src/Room.c index f61a2af..65a7703 100644 --- a/src/Room.c +++ b/src/Room.c @@ -50,8 +50,8 @@ #include #include -#define IsState(p, typ, key) (StrEquals(p->type, typ) && \ - StrEquals(p->state_key, key)) +#define IsState(p, typ, key) (StrEquals((p)->type, typ) && \ + StrEquals((p)->state_key, key)) struct Room { @@ -597,6 +597,7 @@ finish: FinishState(pl); } /* Finds the power level of an user before [e_id] was sent. */ +/* TODO: The creator should have PL100 by default. */ static int64_t RoomUserPL(Room * room, HashMap *state, char *user) { @@ -854,7 +855,7 @@ ConsiderAuthEventsV1(Room * room, PduV1 pdu) /* Step 2.4: If there is no m.room.create event among the entries, * reject. */ - if (!room_create && IsState((&auth_pdu), "m.room.create", "")) + if (!room_create && IsState(&auth_pdu, "m.room.create", "")) { room_create = true; /* Here, we check for the opposite. */ } diff --git a/src/Routes/RouteSync.c b/src/Routes/RouteSync.c index e5df807..ecfc687 100644 --- a/src/Routes/RouteSync.c +++ b/src/Routes/RouteSync.c @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -58,6 +59,28 @@ StripStateEventSync(HashMap *pdu) return ret; } +static bool +IsRoomFiltered(Filter *filter, char *roomID) +{ + size_t i, count; + if (!filter || !roomID) + { + return false; + } + + count = ArraySize(filter->room.not_rooms); + for (i = 0; i < count; i++) + { + char *notRoom = ArrayGet(filter->room.not_rooms, i); + if (StrEquals(roomID, notRoom)) + { + return true; + } + } + /* TODO: Consider rooms */ + return true; +} + ROUTE_IMPL(RouteSync, path, argp) { RouteArgs *args = argp; @@ -66,6 +89,7 @@ ROUTE_IMPL(RouteSync, path, argp) HashMap *params = NULL; HashMap *response = NULL; SyncResponse sync = { 0 }; + Filter filterData = { 0 }; Array *invites; Array *joins; @@ -77,6 +101,7 @@ ROUTE_IMPL(RouteSync, path, argp) char *nextBatch = NULL; char *currBatch = NULL; char *timeout = NULL; + char *filter = NULL; char *err; @@ -111,8 +136,29 @@ ROUTE_IMPL(RouteSync, path, argp) params = HttpRequestParams(args->context); prevBatch = HashMapGet(params, "since"); timeout = HashMapGet(params, "timeout"); + filter = HashMapGet(params, "filter"); timeoutDuration = atoi(timeout); + if (filter && *filter != '{') + { + /* The filter must be located in the database */ + DbRef *filterRef = DbLock(db, 3, + "filters", UserGetName(user), filter + ); + HashMap *filterJson = DbJson(filterRef); + + if (!FilterFromJson(filterJson, &filterData, &err)) + { + HttpResponseStatus(args->context, HTTP_BAD_REQUEST); + response = MatrixErrorCreate(M_BAD_JSON, err); + + DbUnlock(db, filterRef); + goto finish; + } + + /* We now grabbed a filter JSON */ + DbUnlock(db, filterRef); + } if (!prevBatch) { @@ -127,10 +173,9 @@ ROUTE_IMPL(RouteSync, path, argp) 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. */ + /* TODO: Using pthreads' condition variables with a timeout would be + * the best way to proceed (as in Parsee's ParseeAwaitStanza function) + */ while (passed < timeoutDuration) { if (UserGetNotification(name)) @@ -158,6 +203,11 @@ ROUTE_IMPL(RouteSync, path, argp) InvitedRooms invited = { 0 }; HashMap *invitedObject; + if (IsRoomFiltered(&filterData, roomId)) + { + continue; + } + invited.invite_state.events = ArrayCreate(); invitedObject = InvitedRoomsToJson(&invited); JsonSet( @@ -173,16 +223,26 @@ ROUTE_IMPL(RouteSync, path, argp) joins = UserGetJoins(user, currBatch); for (i = 0; i < ArraySize(joins); i++) { + /* TODO: Rename these variables */ char *roomId = ArrayGet(joins, i); - Array *el = UserGetEvents(user, currBatch, roomId); + Array *el; size_t j; - Room *r = RoomLock(db, roomId); - HashMap *state = StateCurrent(r); + Room *r; + HashMap *state; char *firstEvent = NULL; JoinedRooms joined = { 0 }; HashMap *joinedObj; char *type, *key, *id; + if (IsRoomFiltered(&filterData, roomId)) + { + continue; + } + + el = UserGetEvents(user, currBatch, roomId); + r = RoomLock(db, roomId); + state = StateCurrent(r); + joined.timeline.events = ArrayCreate(); for (j = 0; j < ArraySize(el); j++) @@ -242,6 +302,7 @@ ROUTE_IMPL(RouteSync, path, argp) response = SyncResponseToJson(&sync); SyncResponseFree(&sync); finish: + FilterFree(&filterData); UserUnlock(user); (void) path; return response;