diff --git a/CHANGES.rst b/CHANGES.rst index 7cf145b3ee..58704bcc25 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,9 +4,7 @@ Changes in Matrix iOS SDK in 0.11.5 (2018-10-) Improvements: * MXSession: Add eventWithEventId:inRoom: method. * MXRoomState: Add pinnedEvents to list pinned events ids. - -Bug fix: -* +* MXServerNotices: Add this class to get notices from the user homeserver. Changes in Matrix iOS SDK in 0.11.4 (2018-09-26) =============================================== diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index 96dbfab2c2..1d4231d245 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -131,6 +131,8 @@ 3291D4D51A68FFEB00C3BA41 /* MXFileRoomStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 3291D4D31A68FFEB00C3BA41 /* MXFileRoomStore.m */; }; 3293C700214BBA4F009B3DDB /* MXPeekingRoomSummary.h in Headers */ = {isa = PBXBuildFile; fileRef = 3293C6FE214BBA4F009B3DDB /* MXPeekingRoomSummary.h */; }; 3293C701214BBA4F009B3DDB /* MXPeekingRoomSummary.m in Sources */ = {isa = PBXBuildFile; fileRef = 3293C6FF214BBA4F009B3DDB /* MXPeekingRoomSummary.m */; }; + 32954019216385F100E300FC /* MXServerNoticeContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 32954017216385F100E300FC /* MXServerNoticeContent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3295401A216385F100E300FC /* MXServerNoticeContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 32954018216385F100E300FC /* MXServerNoticeContent.m */; }; 329571931B0240CE00ABB3BA /* MXVoIPTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 329571921B0240CE00ABB3BA /* MXVoIPTests.m */; }; 329571991B024D2B00ABB3BA /* MXMockCallStack.m in Sources */ = {isa = PBXBuildFile; fileRef = 329571961B024D2B00ABB3BA /* MXMockCallStack.m */; }; 3295719A1B024D2B00ABB3BA /* MXMockCallStackCall.m in Sources */ = {isa = PBXBuildFile; fileRef = 329571981B024D2B00ABB3BA /* MXMockCallStackCall.m */; }; @@ -171,6 +173,8 @@ 32A31BC520D3FFB0005916C7 /* MXFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A31BC320D3FFB0005916C7 /* MXFilter.m */; }; 32A31BC820D401FC005916C7 /* MXRoomFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 32A31BC620D401FC005916C7 /* MXRoomFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32A31BC920D401FC005916C7 /* MXRoomFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A31BC720D401FC005916C7 /* MXRoomFilter.m */; }; + 32A9770421626E5C00919CC0 /* MXServerNotices.h in Headers */ = {isa = PBXBuildFile; fileRef = 32A9770221626E5C00919CC0 /* MXServerNotices.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 32A9770521626E5C00919CC0 /* MXServerNotices.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A9770321626E5C00919CC0 /* MXServerNotices.m */; }; 32A9E8241EF4026E0081358A /* MXBackgroundModeHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 32A9E8211EF4026E0081358A /* MXBackgroundModeHandler.h */; }; 32A9E8251EF4026E0081358A /* MXUIKitBackgroundModeHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 32A9E8221EF4026E0081358A /* MXUIKitBackgroundModeHandler.h */; }; 32A9E8261EF4026E0081358A /* MXUIKitBackgroundModeHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A9E8231EF4026E0081358A /* MXUIKitBackgroundModeHandler.m */; }; @@ -431,6 +435,8 @@ 3291D4D31A68FFEB00C3BA41 /* MXFileRoomStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXFileRoomStore.m; sourceTree = ""; }; 3293C6FE214BBA4F009B3DDB /* MXPeekingRoomSummary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXPeekingRoomSummary.h; sourceTree = ""; }; 3293C6FF214BBA4F009B3DDB /* MXPeekingRoomSummary.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXPeekingRoomSummary.m; sourceTree = ""; }; + 32954017216385F100E300FC /* MXServerNoticeContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXServerNoticeContent.h; sourceTree = ""; }; + 32954018216385F100E300FC /* MXServerNoticeContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXServerNoticeContent.m; sourceTree = ""; }; 329571921B0240CE00ABB3BA /* MXVoIPTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXVoIPTests.m; sourceTree = ""; }; 329571951B024D2B00ABB3BA /* MXMockCallStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXMockCallStack.h; sourceTree = ""; }; 329571961B024D2B00ABB3BA /* MXMockCallStack.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXMockCallStack.m; sourceTree = ""; }; @@ -473,6 +479,8 @@ 32A31BC320D3FFB0005916C7 /* MXFilter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXFilter.m; sourceTree = ""; }; 32A31BC620D401FC005916C7 /* MXRoomFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXRoomFilter.h; sourceTree = ""; }; 32A31BC720D401FC005916C7 /* MXRoomFilter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXRoomFilter.m; sourceTree = ""; }; + 32A9770221626E5C00919CC0 /* MXServerNotices.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXServerNotices.h; sourceTree = ""; }; + 32A9770321626E5C00919CC0 /* MXServerNotices.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXServerNotices.m; sourceTree = ""; }; 32A9E8211EF4026E0081358A /* MXBackgroundModeHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXBackgroundModeHandler.h; sourceTree = ""; }; 32A9E8221EF4026E0081358A /* MXUIKitBackgroundModeHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXUIKitBackgroundModeHandler.h; sourceTree = ""; }; 32A9E8231EF4026E0081358A /* MXUIKitBackgroundModeHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXUIKitBackgroundModeHandler.m; sourceTree = ""; }; @@ -714,6 +722,8 @@ 32A9E8211EF4026E0081358A /* MXBackgroundModeHandler.h */, 32A9E8221EF4026E0081358A /* MXUIKitBackgroundModeHandler.h */, 32A9E8231EF4026E0081358A /* MXUIKitBackgroundModeHandler.m */, + 32A9770221626E5C00919CC0 /* MXServerNotices.h */, + 32A9770321626E5C00919CC0 /* MXServerNotices.m */, ); path = Utils; sourceTree = ""; @@ -870,6 +880,8 @@ B17982F22119E4A1001FD722 /* MXRoomCreateContent.m */, B17982EF2119E49F001FD722 /* MXRoomPredecessorInfo.h */, B17982F32119E4A1001FD722 /* MXRoomPredecessorInfo.m */, + 32954017216385F100E300FC /* MXServerNoticeContent.h */, + 32954018216385F100E300FC /* MXServerNoticeContent.m */, 323F8862212D4E470001C73C /* MXMatrixVersions.h */, 323F8863212D4E470001C73C /* MXMatrixVersions.m */, ); @@ -1231,6 +1243,7 @@ 321B413F1E09937E009EEEC7 /* MXRoomSummary.h in Headers */, B17982F52119E4A2001FD722 /* MXRoomCreateContent.h in Headers */, 32DC15CF1A8CF7AE006F9AD3 /* MXPushRuleConditionChecker.h in Headers */, + 32954019216385F100E300FC /* MXServerNoticeContent.h in Headers */, 327187851DA7D0220071C818 /* MXOlmDecryption.h in Headers */, 32D7767D1A27860600FC4AA2 /* MXMemoryStore.h in Headers */, 32CE6FB81A409B1F00317F1E /* MXFileStoreMetaData.h in Headers */, @@ -1271,6 +1284,7 @@ 329FB1791A0A74B100A5E88E /* MXTools.h in Headers */, 322691321E5EF77D00966A6E /* MXDeviceListOperation.h in Headers */, 32481A841C03572900782AD3 /* MXRoomAccountData.h in Headers */, + 32A9770421626E5C00919CC0 /* MXServerNotices.h in Headers */, F08B8D5C1E014711006171A8 /* NSData+MatrixSDK.h in Headers */, C60165381E3AA57900B92CFA /* MXSDKOptions.h in Headers */, 3281E8B919E42DFE00976E1A /* MXJSONModels.h in Headers */, @@ -1501,6 +1515,7 @@ 322A51C41D9AC8FE00C8536D /* MXCryptoAlgorithms.m in Sources */, 329FB1761A0A3A1600A5E88E /* MXRoomMember.m in Sources */, 323360701A403A0D0071A488 /* MXFileStore.m in Sources */, + 32A9770521626E5C00919CC0 /* MXServerNotices.m in Sources */, 32D7767E1A27860600FC4AA2 /* MXMemoryStore.m in Sources */, 32A151531DAF8A7200400192 /* MXQueuedEncryption.m in Sources */, C6D5D60A1E4FA74000706C0F /* MXEnumConstants.swift in Sources */, @@ -1564,6 +1579,7 @@ 320DFDE119DD99B60068622A /* MXSession.m in Sources */, B17982F62119E4A2001FD722 /* MXRoomTombStoneContent.m in Sources */, C602B58E1F22A8D700B67D87 /* MXImage.swift in Sources */, + 3295401A216385F100E300FC /* MXServerNoticeContent.m in Sources */, 32A151491DAF7C0C00400192 /* MXKey.m in Sources */, F0C34CBB1C18C93700C36F09 /* MXSDKOptions.m in Sources */, 320BBF441D6C81550079890E /* MXEventsEnumeratorOnArray.m in Sources */, diff --git a/MatrixSDK/JSONModels/MXEvent.h b/MatrixSDK/JSONModels/MXEvent.h index 5d51f14289..993cd94f38 100644 --- a/MatrixSDK/JSONModels/MXEvent.h +++ b/MatrixSDK/JSONModels/MXEvent.h @@ -126,6 +126,7 @@ FOUNDATION_EXPORT NSString *const kMXMessageTypeAudio; FOUNDATION_EXPORT NSString *const kMXMessageTypeVideo; FOUNDATION_EXPORT NSString *const kMXMessageTypeLocation; FOUNDATION_EXPORT NSString *const kMXMessageTypeFile; +FOUNDATION_EXPORT NSString *const kMXMessageTypeServerNotice; /** Prefix used for id of temporary local event. diff --git a/MatrixSDK/JSONModels/MXEvent.m b/MatrixSDK/JSONModels/MXEvent.m index 069f94bb2e..b9f399f972 100644 --- a/MatrixSDK/JSONModels/MXEvent.m +++ b/MatrixSDK/JSONModels/MXEvent.m @@ -59,14 +59,15 @@ NSString *const kMXEventTypeStringSticker = @"m.sticker"; NSString *const kMXEventTypeStringRoomTombStone = @"m.room.tombstone"; -NSString *const kMXMessageTypeText = @"m.text"; -NSString *const kMXMessageTypeEmote = @"m.emote"; -NSString *const kMXMessageTypeNotice = @"m.notice"; -NSString *const kMXMessageTypeImage = @"m.image"; -NSString *const kMXMessageTypeAudio = @"m.audio"; -NSString *const kMXMessageTypeVideo = @"m.video"; -NSString *const kMXMessageTypeLocation = @"m.location"; -NSString *const kMXMessageTypeFile = @"m.file"; +NSString *const kMXMessageTypeText = @"m.text"; +NSString *const kMXMessageTypeEmote = @"m.emote"; +NSString *const kMXMessageTypeNotice = @"m.notice"; +NSString *const kMXMessageTypeImage = @"m.image"; +NSString *const kMXMessageTypeAudio = @"m.audio"; +NSString *const kMXMessageTypeVideo = @"m.video"; +NSString *const kMXMessageTypeLocation = @"m.location"; +NSString *const kMXMessageTypeFile = @"m.file"; +NSString *const kMXMessageTypeServerNotice = @"m.server_notice"; NSString *const kMXEventLocalEventIdPrefix = @"kMXEventLocalId_"; diff --git a/MatrixSDK/JSONModels/MXServerNoticeContent.h b/MatrixSDK/JSONModels/MXServerNoticeContent.h new file mode 100644 index 0000000000..aa20f32b46 --- /dev/null +++ b/MatrixSDK/JSONModels/MXServerNoticeContent.h @@ -0,0 +1,50 @@ +/* + Copyright 2018 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#import +#import "MXJSONModel.h" + + +FOUNDATION_EXPORT NSString *const kMXServerNoticeTypeUsageLimitReached; + +/** + * Content of a m.server_notice event message. + */ +@interface MXServerNoticeContent : MXJSONModel + +/** + The kind of user limit, generally is monthly_active_user. + */ +@property (nonatomic, readonly ) NSString *limitType; + +/** + An URI to contact the homeserver administrator + */ +@property (nonatomic, readonly ) NSString *adminContact; + +/** + The notice type. + Like kMXServerNoticeTypeUsageLimitReached. + */ +@property (nonatomic, readonly ) NSString *serverNoticeType; + +/** + Inidicate if it is a notice for usage limit reached. + */ +@property (nonatomic, readonly ) BOOL isServerNoticeUsageLimit; + +@end diff --git a/MatrixSDK/JSONModels/MXServerNoticeContent.m b/MatrixSDK/JSONModels/MXServerNoticeContent.m new file mode 100644 index 0000000000..e4aaa2af10 --- /dev/null +++ b/MatrixSDK/JSONModels/MXServerNoticeContent.m @@ -0,0 +1,42 @@ +/* + Copyright 2018 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "MXServerNoticeContent.h" + +NSString *const kMXServerNoticeTypeUsageLimitReached = @"m.server_notice.usage_limit_reached"; + + +@implementation MXServerNoticeContent + ++ (id)modelFromJSON:(NSDictionary *)JSONDictionary +{ + MXServerNoticeContent* serverNoticeUsageLimitContent = [MXServerNoticeContent new]; + if (serverNoticeUsageLimitContent) + { + MXJSONModelSetString(serverNoticeUsageLimitContent->_limitType, JSONDictionary[@"limit_type"]); + MXJSONModelSetString(serverNoticeUsageLimitContent->_adminContact, JSONDictionary[@"admin_contact"]); + MXJSONModelSetString(serverNoticeUsageLimitContent->_serverNoticeType, JSONDictionary[@"server_notice_type"]); + } + + return serverNoticeUsageLimitContent; +} + +- (BOOL)isServerNoticeUsageLimit +{ + return [kMXServerNoticeTypeUsageLimitReached isEqualToString:_serverNoticeType]; +} + +@end diff --git a/MatrixSDK/MatrixSDK.h b/MatrixSDK/MatrixSDK.h index f299eabf8c..debc3e4212 100644 --- a/MatrixSDK/MatrixSDK.h +++ b/MatrixSDK/MatrixSDK.h @@ -58,3 +58,5 @@ FOUNDATION_EXPORT NSString *MatrixSDKVersion; #import "MXCallKitConfiguration.h" #import "MXGroup.h" + +#import "MXServerNotices.h" diff --git a/MatrixSDK/Utils/MXServerNotices.h b/MatrixSDK/Utils/MXServerNotices.h new file mode 100644 index 0000000000..91343d85be --- /dev/null +++ b/MatrixSDK/Utils/MXServerNotices.h @@ -0,0 +1,74 @@ +/* + Copyright 2018 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +#import "MXServerNoticeContent.h" + +@class MXSession; + +@protocol MXServerNoticesDelegate; + +/** + A `MXServerNotices` instance is responsible for listening to messages from the + user homeserver. + + It implements https://github.com/matrix-org/matrix-doc/issues/1452.system where + this communication channel is based on system alert rooms and their pinning events. + */ +@interface MXServerNotices : NSObject + +/** + Create the `MXServerNotices` instance. + + @param mxSession the mxSession to the home server. + @return the newly created MXNotification instance. + */ +- (instancetype)initWithMatrixSession:(MXSession*)mxSession; + +/** + Stop checking homeserver notices. + */ +- (void)close; + +/** + If not nil, there is an outgoing usage limitation. + */ +@property (nonatomic, readonly) MXServerNoticeContent *usageLimit; + +/** + The delegate. + */ +@property (nonatomic, weak) id delegate; + +@end + + +#pragma mark - MXServerNoticesDelegate + +/** + Delegate for `MXCall` object + */ +@protocol MXServerNoticesDelegate + +/** + Tells the delegate that there is a change in server notices + + @param serverNotices the instance that changes. + */ +- (void)serverNoticesDidChangeState:(MXServerNotices *)serverNotices; + +@end diff --git a/MatrixSDK/Utils/MXServerNotices.m b/MatrixSDK/Utils/MXServerNotices.m new file mode 100644 index 0000000000..4124f4862d --- /dev/null +++ b/MatrixSDK/Utils/MXServerNotices.m @@ -0,0 +1,198 @@ +/* + Copyright 2018 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "MXServerNotices.h" + +#import "MXSession.h" +#import "MXTools.h" + +// We need to fetch each pinned message individually (if we don't already have it) +// so each pinned message may trigger a request. Limit the number per room for sanity. +// NB. this is just for server notices rather than pinned messages in general. +NSUInteger const kMXServerNoticesMaxPinnedNoticesPerRoom = 2; + + +@interface MXServerNotices () +{ + MXSession *mxSession; + + /** + The listener to events that can indicate a change in server notices. + */ + id eventsListener; +} +@end + +@implementation MXServerNotices + +- (instancetype)initWithMatrixSession:(MXSession *)matrixSession +{ + self = [super init]; + if (self) + { + mxSession = matrixSession; + } + return self; +} + +- (void)close +{ + if (eventsListener) + { + [mxSession removeListener:eventsListener]; + eventsListener = nil; + } + + _delegate = nil; + mxSession = nil; +} + +- (void)setDelegate:(id)delegate +{ + _delegate = delegate; + + if (!eventsListener) + { + // m.room.pinned_events and m.tag are events to listen + MXWeakify(self); + eventsListener = [mxSession listenToEventsOfTypes:@[kMXEventTypeStringRoomPinnedEvents, kMXEventTypeStringRoomTag] + onEvent:^(MXEvent *event, MXTimelineDirection direction, id customObject) + { + MXStrongifyAndReturnIfNil(self); + + if (direction == MXTimelineDirectionForwards) + { + if (event.eventType == MXEventTypeRoomPinnedEvents) + { + // In case of pinned events, we are interested only by those + // in system alert rooms + for (MXRoom *serverNoticeRoom in [self->mxSession roomsWithTag:kMXRoomTagServerNotice]) + { + if ([serverNoticeRoom.roomId isEqualToString:event.roomId]) + { + [self checkState]; + break; + } + } + } + else + { + // In case of tags change, recompute from start + [self checkState]; + } + } + }]; + + // Get the current state + [self checkState]; + } +} + +#pragma mark - Private methods + +/** + Set the new usage limit and informs the delegate if necessary. + + @param usageLimit the new usage limit. + */ +- (void)setUsageLimit:(MXServerNoticeContent *)usageLimit +{ + if (_usageLimit != usageLimit) + { + _usageLimit = usageLimit; + + if (_delegate) + { + [_delegate serverNoticesDidChangeState:self]; + } + } +} + +/** + Compute the current server notices state + */ +- (void)checkState +{ + // Check all pinning events of system alert rooms + [self serverNoticePinnedEvents:^(NSArray *pinnedEvents) { + + for (MXEvent *pinnedEvent in pinnedEvents) + { + if (pinnedEvent.eventType == MXEventTypeRoomMessage + && [pinnedEvent.content[@"msgtype"] isEqualToString:kMXMessageTypeServerNotice]) + { + // For now, there is only one server notice, usage limit + self.usageLimit = [MXServerNoticeContent modelFromJSON:pinnedEvent.content]; + break; + } + } + }]; +} + +/** + Return all pinned events in server notice rooms. + + @param complete A block object called when the operation completes. +*/ +- (void)serverNoticePinnedEvents:(nonnull void (^)(NSArray *pinnedEvents))complete +{ + NSMutableArray *serverNoticePinnedEvents = [NSMutableArray array]; + + dispatch_group_t group = dispatch_group_create(); + + // Get server notice rooms + for (MXRoom *serverNoticeRoom in [mxSession roomsWithTag:kMXRoomTagServerNotice]) + { + dispatch_group_enter(group); + + // Get pinned events ids + MXWeakify(self); + [serverNoticeRoom state:^(MXRoomState *roomState) { + MXStrongifyAndReturnIfNil(self); + + // Apply kMXServerNoticesMaxPinnedNoticesPerRoom rule + NSArray *pinnedEventIds = roomState.pinnedEvents; + if (pinnedEventIds.count > kMXServerNoticesMaxPinnedNoticesPerRoom) + { + pinnedEventIds = [pinnedEventIds subarrayWithRange:NSMakeRange(0, kMXServerNoticesMaxPinnedNoticesPerRoom)]; + } + + // Get pinned events + for (NSString *pinnedEventId in pinnedEventIds) + { + dispatch_group_enter(group); + [self->mxSession eventWithEventId:pinnedEventId inRoom:serverNoticeRoom.roomId success:^(MXEvent *event) { + + [serverNoticePinnedEvents addObject:event]; + dispatch_group_leave(group); + + } failure:^(NSError *error) { + + NSLog(@"[MXServerNotices] Failed to get pinned event %@. Continue anyway", pinnedEventId); + dispatch_group_leave(group); + }]; + } + + dispatch_group_leave(group); + }]; + } + + dispatch_group_notify(group, dispatch_get_main_queue(), ^{ + complete(serverNoticePinnedEvents); + }); +} + +@end