2021-12-03 10:47:24 +00:00
/ *
Copyright 2015 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd
Copyright 2019 The Matrix . org Foundation C . I . C
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 "MXKAccount.h"
# import "MXKAccountManager.h"
# import "MXKRoomDataSourceManager.h"
# import "MXKEventFormatter.h"
# import "MXKTools.h"
# import "MXKContactManager.h"
# import "MXKConstants.h"
# import "NSBundle+MatrixKit.h"
# import < AFNetworking / AFNetworking . h >
# import < MatrixSDK / MXBackgroundModeHandler . h >
# import "MXKSwiftHeader.h"
2022-01-13 17:33:51 +00:00
# import "GeneratedInterface-Swift.h"
2021-12-03 10:47:24 +00:00
NSString * const kMXKAccountUserInfoDidChangeNotification = @ "kMXKAccountUserInfoDidChangeNotification" ;
NSString * const kMXKAccountAPNSActivityDidChangeNotification = @ "kMXKAccountAPNSActivityDidChangeNotification" ;
NSString * const kMXKAccountPushKitActivityDidChangeNotification = @ "kMXKAccountPushKitActivityDidChangeNotification" ;
NSString * const kMXKAccountErrorDomain = @ "kMXKAccountErrorDomain" ;
static MXKAccountOnCertificateChange _onCertificateChangeBlock ;
/ * *
HTTP status codes for error cases on initial sync requests , for which errors will not be propagated to the client .
* /
static NSArray < NSNumber * > * initialSyncSilentErrorsHTTPStatusCodes ;
@ interface MXKAccount ( )
{
// We will notify user only once on session failure
BOOL notifyOpenSessionFailure ;
// The timer used to postpone server sync on failure
NSTimer * initialServerSyncTimer ;
// Reachability observer
id reachabilityObserver ;
// Session state observer
id sessionStateObserver ;
// Handle user ' s settings change
id userUpdateListener ;
// Used for logging application start up
NSDate * openSessionStartDate ;
// Event notifications listener
id notificationCenterListener ;
// Internal list of ignored rooms
NSMutableArray * ignoredRooms ;
// If a server sync is in progress , the pause is delayed at the end of sync ( except if resume is called ) .
BOOL isPauseRequested ;
// Background sync management
MXOnBackgroundSyncDone backgroundSyncDone ;
MXOnBackgroundSyncFail backgroundSyncFails ;
NSTimer * backgroundSyncTimer ;
// Observe UIApplicationSignificantTimeChangeNotification to refresh MXRoomSummaries on time formatting change .
id UIApplicationSignificantTimeChangeNotificationObserver ;
// Observe NSCurrentLocaleDidChangeNotification to refresh MXRoomSummaries on time formatting change .
id NSCurrentLocaleDidChangeNotificationObserver ;
}
@ property ( nonatomic , strong ) id < MXBackgroundTask > backgroundTask ;
@ property ( nonatomic , strong ) id < MXBackgroundTask > backgroundSyncBgTask ;
@ end
@ implementation MXKAccount
2022-01-06 20:35:37 +00:00
@ synthesize mxSession , mxRestClient ;
2021-12-03 10:47:24 +00:00
@ synthesize userPresence ;
@ synthesize userTintColor ;
@ synthesize hideUserPresence ;
+ ( void ) load
{
static dispatch_once _t onceToken ;
dispatch_once ( & onceToken , ^ {
initialSyncSilentErrorsHTTPStatusCodes = @ [
@ ( 504 ) ,
@ ( 522 ) ,
@ ( 524 ) ,
@ ( 599 )
] ;
} ) ;
}
+ ( void ) registerOnCertificateChangeBlock : ( MXKAccountOnCertificateChange ) onCertificateChangeBlock
{
_onCertificateChangeBlock = onCertificateChangeBlock ;
}
+ ( UIColor * ) presenceColor : ( MXPresence ) presence
{
switch ( presence )
{
case MXPresenceOnline :
return [ [ MXKAppSettings standardAppSettings ] presenceColorForOnlineUser ] ;
case MXPresenceUnavailable :
return [ [ MXKAppSettings standardAppSettings ] presenceColorForUnavailableUser ] ;
case MXPresenceOffline :
return [ [ MXKAppSettings standardAppSettings ] presenceColorForOfflineUser ] ;
case MXPresenceUnknown :
default :
return nil ;
}
}
- ( instancetype ) initWithCredentials : ( MXCredentials * ) credentials
{
if ( self = [ super init ] )
{
notifyOpenSessionFailure = YES ;
// Report credentials and alloc REST client .
2022-01-06 20:35:37 +00:00
_mxCredentials = credentials ;
2021-12-03 10:47:24 +00:00
[ self prepareRESTClient ] ;
userPresence = MXPresenceUnknown ;
// Refresh device information
[ self loadDeviceInformation : nil failure : nil ] ;
[ self registerAccountDataDidChangeIdentityServerNotification ] ;
[ self registerIdentityServiceDidChangeAccessTokenNotification ] ;
}
return self ;
}
- ( void ) dealloc
{
[ self closeSession : NO ] ;
mxSession = nil ;
[ mxRestClient close ] ;
mxRestClient = nil ;
}
# pragma mark - NSCoding
- ( id ) initWithCoder : ( NSCoder * ) coder
{
2022-01-06 20:35:37 +00:00
self = [ super initWithCoder : coder ] ;
2021-12-03 10:47:24 +00:00
if ( self )
{
notifyOpenSessionFailure = YES ;
[ self prepareRESTClient ] ;
[ self registerAccountDataDidChangeIdentityServerNotification ] ;
[ self registerIdentityServiceDidChangeAccessTokenNotification ] ;
userPresence = MXPresenceUnknown ;
// Refresh device information
[ self loadDeviceInformation : nil failure : nil ] ;
}
return self ;
}
# pragma mark - Properties
- ( void ) setIdentityServerURL : ( NSString * ) identityServerURL
{
if ( identityServerURL . length )
{
_identityServerURL = identityServerURL ;
2022-01-06 20:35:37 +00:00
self . mxCredentials . identityServer = identityServerURL ;
2021-12-03 10:47:24 +00:00
// Update services used in MXSession
2022-01-06 20:35:37 +00:00
[ mxSession setIdentityServer : self . mxCredentials . identityServer andAccessToken : self . mxCredentials . identityServerAccessToken ] ;
2021-12-03 10:47:24 +00:00
}
else
{
_identityServerURL = nil ;
[ mxSession setIdentityServer : nil andAccessToken : nil ] ;
}
// Archive updated field
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
}
- ( void ) setAntivirusServerURL : ( NSString * ) antivirusServerURL
{
_antivirusServerURL = antivirusServerURL ;
// Update the current session if any
[ mxSession setAntivirusServerURL : antivirusServerURL ] ;
// Archive updated field
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
}
- ( void ) setPushGatewayURL : ( NSString * ) pushGatewayURL
{
_pushGatewayURL = pushGatewayURL . length ? pushGatewayURL : nil ;
MXLogDebug ( @ "[MXKAccount][Push] setPushGatewayURL: %@" , _pushGatewayURL ) ;
// Archive updated field
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
}
- ( NSString * ) userDisplayName
{
if ( mxSession )
{
return mxSession . myUser . displayname ;
}
return nil ;
}
- ( NSString * ) userAvatarUrl
{
if ( mxSession )
{
return mxSession . myUser . avatarUrl ;
}
return nil ;
}
- ( NSString * ) fullDisplayName
{
if ( self . userDisplayName . length )
{
2022-01-06 20:35:37 +00:00
return [ NSString stringWithFormat : @ "%@ (%@)" , self . userDisplayName , self . mxCredentials . userId ] ;
2021-12-03 10:47:24 +00:00
}
else
{
2022-01-06 20:35:37 +00:00
return self . mxCredentials . userId ;
2021-12-03 10:47:24 +00:00
}
}
- ( NSArray < NSString * > * ) linkedEmails
{
NSMutableArray < NSString * > * linkedEmails = [ NSMutableArray array ] ;
2022-01-06 20:35:37 +00:00
for ( MXThirdPartyIdentifier * threePID in self . threePIDs )
2021-12-03 10:47:24 +00:00
{
if ( [ threePID . medium isEqualToString : kMX3PIDMediumEmail ] )
{
[ linkedEmails addObject : threePID . address ] ;
}
}
return linkedEmails ;
}
- ( NSArray < NSString * > * ) linkedPhoneNumbers
{
NSMutableArray < NSString * > * linkedPhoneNumbers = [ NSMutableArray array ] ;
2022-01-06 20:35:37 +00:00
for ( MXThirdPartyIdentifier * threePID in self . threePIDs )
2021-12-03 10:47:24 +00:00
{
if ( [ threePID . medium isEqualToString : kMX3PIDMediumMSISDN ] )
{
[ linkedPhoneNumbers addObject : threePID . address ] ;
}
}
return linkedPhoneNumbers ;
}
- ( UIColor * ) userTintColor
{
if ( ! userTintColor )
{
2022-01-06 20:35:37 +00:00
userTintColor = [ MXKTools colorWithRGBValue : [ self . mxCredentials . userId hash ] ] ;
2021-12-03 10:47:24 +00:00
}
return userTintColor ;
}
- ( BOOL ) pushNotificationServiceIsActive
{
2022-01-06 20:35:37 +00:00
BOOL pushNotificationServiceIsActive = ( [ [ MXKAccountManager sharedManager ] isAPNSAvailable ] && self . hasPusherForPushNotifications && mxSession ) ;
2021-12-03 10:47:24 +00:00
MXLogDebug ( @ "[MXKAccount][Push] pushNotificationServiceIsActive: %@" , @ ( pushNotificationServiceIsActive ) ) ;
return pushNotificationServiceIsActive ;
}
- ( void ) enablePushNotifications : ( BOOL ) enable
success : ( void ( ^ ) ( void ) ) success
failure : ( void ( ^ ) ( NSError * ) ) failure
{
MXLogDebug ( @ "[MXKAccount][Push] enablePushNotifications: %@" , @ ( enable ) ) ;
if ( enable )
{
if ( [ [ MXKAccountManager sharedManager ] isAPNSAvailable ] )
{
MXLogDebug ( @ "[MXKAccount][Push] enablePushNotifications: Enable Push for %@ account" , self . mxCredentials . userId ) ;
// Create / restore the pusher
[ self enableAPNSPusher : YES success : ^ {
MXLogDebug ( @ "[MXKAccount][Push] enablePushNotifications: Enable Push: Success" ) ;
if ( success )
{
success ( ) ;
}
} failure : ^ ( NSError * error ) {
MXLogDebug ( @ "[MXKAccount][Push] enablePushNotifications: Enable Push: Error: %@" , error ) ;
if ( failure )
{
failure ( error ) ;
}
} ] ;
}
else
{
MXLogDebug ( @ "[MXKAccount][Push] enablePushNotifications: Error: Cannot enable Push" ) ;
NSError * error = [ NSError errorWithDomain : kMXKAccountErrorDomain
code : 0
userInfo : @ {
NSLocalizedDescriptionKey :
[ MatrixKitL10n accountErrorPushNotAllowed ]
} ] ;
if ( failure )
{
failure ( error ) ;
}
}
}
2022-01-06 20:35:37 +00:00
else if ( self . hasPusherForPushNotifications )
2021-12-03 10:47:24 +00:00
{
MXLogDebug ( @ "[MXKAccount][Push] enablePushNotifications: Disable APNS for %@ account" , self . mxCredentials . userId ) ;
// Delete the pusher , report the new value only on success .
[ self enableAPNSPusher : NO
success : ^ {
MXLogDebug ( @ "[MXKAccount][Push] enablePushNotifications: Disable Push: Success" ) ;
if ( success )
{
success ( ) ;
}
} failure : ^ ( NSError * error ) {
MXLogDebug ( @ "[MXKAccount][Push] enablePushNotifications: Disable Push: Error: %@" , error ) ;
if ( failure )
{
failure ( error ) ;
}
} ] ;
}
}
- ( BOOL ) isPushKitNotificationActive
{
2022-01-06 20:35:37 +00:00
BOOL isPushKitNotificationActive = ( [ [ MXKAccountManager sharedManager ] isPushAvailable ] && self . hasPusherForPushKitNotifications && mxSession ) ;
2021-12-03 10:47:24 +00:00
MXLogDebug ( @ "[MXKAccount][Push] isPushKitNotificationActive: %@" , @ ( isPushKitNotificationActive ) ) ;
return isPushKitNotificationActive ;
}
- ( void ) enablePushKitNotifications : ( BOOL ) enable
success : ( void ( ^ ) ( void ) ) success
failure : ( void ( ^ ) ( NSError * ) ) failure
{
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitNotifications: %@" , @ ( enable ) ) ;
if ( enable )
{
if ( [ [ MXKAccountManager sharedManager ] isPushAvailable ] )
{
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitNotifications: Enable Push for %@ account" , self . mxCredentials . userId ) ;
// Create / restore the pusher
[ self enablePushKitPusher : YES success : ^ {
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitNotifications: Enable Push: Success" ) ;
if ( success )
{
success ( ) ;
}
} failure : ^ ( NSError * error ) {
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitNotifications: Enable Push: Error: %@" , error ) ;
if ( failure )
{
failure ( error ) ;
}
} ] ;
}
else
{
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitNotifications: Error: Cannot enable Push" ) ;
NSError * error = [ NSError errorWithDomain : kMXKAccountErrorDomain
code : 0
userInfo : @ {
NSLocalizedDescriptionKey :
[ MatrixKitL10n accountErrorPushNotAllowed ]
} ] ;
failure ( error ) ;
}
}
2022-01-06 20:35:37 +00:00
else if ( self . hasPusherForPushKitNotifications )
2021-12-03 10:47:24 +00:00
{
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitNotifications: Disable Push for %@ account" , self . mxCredentials . userId ) ;
// Delete the pusher , report the new value only on success .
[ self enablePushKitPusher : NO success : ^ {
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitNotifications: Disable Push: Success" ) ;
if ( success )
{
success ( ) ;
}
} failure : ^ ( NSError * error ) {
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitNotifications: Disable Push: Error: %@" , error ) ;
if ( failure )
{
failure ( error ) ;
}
} ] ;
}
else
{
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitNotifications: PushKit is already disabled for %@" , self . mxCredentials . userId ) ;
if ( success )
{
success ( ) ;
}
}
}
- ( void ) setEnableInAppNotifications : ( BOOL ) enableInAppNotifications
{
MXLogDebug ( @ "[MXKAccount] setEnableInAppNotifications: %@" , @ ( enableInAppNotifications ) ) ;
_enableInAppNotifications = enableInAppNotifications ;
// Archive updated field
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
}
- ( void ) setDisabled : ( BOOL ) disabled
{
if ( _disabled ! = disabled )
{
_disabled = disabled ;
if ( _disabled )
{
[ self deletePusher ] ;
[ self enablePushKitNotifications : NO success : nil failure : nil ] ;
// Close session ( keep the storage ) .
[ self closeSession : NO ] ;
}
else if ( ! mxSession )
{
// Open a new matrix session
id < MXStore > store = [ [ [ MXKAccountManager sharedManager ] . storeClass alloc ] init ] ;
[ self openSessionWithStore : store ] ;
}
// Archive updated field
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
}
}
- ( void ) setWarnedAboutEncryption : ( BOOL ) warnedAboutEncryption
{
_warnedAboutEncryption = warnedAboutEncryption ;
// Archive updated field
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
}
- ( NSMutableDictionary < NSString * , id < NSCoding > > * ) others
{
if ( _others = = nil )
{
_others = [ NSMutableDictionary dictionary ] ;
}
return _others ;
}
# pragma mark - Matrix user ' s profile
- ( void ) setUserDisplayName : ( NSString * ) displayname success : ( void ( ^ ) ( void ) ) success failure : ( void ( ^ ) ( NSError * error ) ) failure
{
if ( mxSession && mxSession . myUser )
{
[ mxSession . myUser setDisplayName : displayname
success : ^ {
if ( success ) {
success ( ) ;
}
2022-01-06 20:35:37 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kMXKAccountUserInfoDidChangeNotification object : self . mxCredentials . userId ] ;
2021-12-03 10:47:24 +00:00
}
failure : failure ] ;
}
else if ( failure )
{
failure ( [ NSError errorWithDomain : kMXKAccountErrorDomain code : 0 userInfo : @ { NSLocalizedDescriptionKey : [ MatrixKitL10n accountErrorMatrixSessionIsNotOpened ] } ] ) ;
}
}
- ( void ) setUserAvatarUrl : ( NSString * ) avatarUrl success : ( void ( ^ ) ( void ) ) success failure : ( void ( ^ ) ( NSError * error ) ) failure
{
if ( mxSession && mxSession . myUser )
{
[ mxSession . myUser setAvatarUrl : avatarUrl
success : ^ {
if ( success ) {
success ( ) ;
}
2022-01-06 20:35:37 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kMXKAccountUserInfoDidChangeNotification object : self . mxCredentials . userId ] ;
2021-12-03 10:47:24 +00:00
}
failure : failure ] ;
}
else if ( failure )
{
failure ( [ NSError errorWithDomain : kMXKAccountErrorDomain code : 0 userInfo : @ { NSLocalizedDescriptionKey : [ MatrixKitL10n accountErrorMatrixSessionIsNotOpened ] } ] ) ;
}
}
- ( void ) changePassword : ( NSString * ) oldPassword with : ( NSString * ) newPassword success : ( void ( ^ ) ( void ) ) success failure : ( void ( ^ ) ( NSError * error ) ) failure
{
if ( mxSession )
{
[ mxRestClient changePassword : oldPassword
with : newPassword
success : ^ {
if ( success ) {
success ( ) ;
}
}
failure : failure ] ;
}
else if ( failure )
{
failure ( [ NSError errorWithDomain : kMXKAccountErrorDomain code : 0 userInfo : @ { NSLocalizedDescriptionKey : [ MatrixKitL10n accountErrorMatrixSessionIsNotOpened ] } ] ) ;
}
}
- ( void ) load3PIDs : ( void ( ^ ) ( void ) ) success failure : ( void ( ^ ) ( NSError * ) ) failure
{
2022-01-06 20:35:37 +00:00
2021-12-03 10:47:24 +00:00
[ mxRestClient threePIDs : ^ ( NSArray < MXThirdPartyIdentifier * > * threePIDs2 ) {
2022-01-06 20:35:37 +00:00
self -> _threePIDs = threePIDs2 ;
2021-12-03 10:47:24 +00:00
// Archive updated field
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
if ( success )
{
success ( ) ;
}
} failure : ^ ( NSError * error ) {
if ( failure )
{
failure ( error ) ;
}
} ] ;
}
- ( void ) loadDeviceInformation : ( void ( ^ ) ( void ) ) success failure : ( void ( ^ ) ( NSError * error ) ) failure
{
2022-01-06 20:35:37 +00:00
if ( self . mxCredentials . deviceId )
2021-12-03 10:47:24 +00:00
{
2022-01-06 20:35:37 +00:00
[ mxRestClient deviceByDeviceId : self . mxCredentials . deviceId success : ^ ( MXDevice * device ) {
2021-12-03 10:47:24 +00:00
self -> _device = device ;
// Archive updated field
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
if ( success )
{
success ( ) ;
}
} failure : ^ ( NSError * error ) {
if ( failure )
{
failure ( error ) ;
}
} ] ;
}
else
{
_device = nil ;
if ( success )
{
success ( ) ;
}
}
}
- ( void ) setUserPresence : ( MXPresence ) presence andStatusMessage : ( NSString * ) statusMessage completion : ( void ( ^ ) ( void ) ) completion
{
userPresence = presence ;
if ( mxSession && ! hideUserPresence )
{
// Update user presence on server side
[ mxSession . myUser setPresence : userPresence
andStatusMessage : statusMessage
success : ^ {
2022-01-06 20:35:37 +00:00
MXLogDebug ( @ "[MXKAccount] %@: set user presence (%lu) succeeded" , self . mxCredentials . userId , ( unsigned long ) self -> userPresence ) ;
2021-12-03 10:47:24 +00:00
if ( completion )
{
completion ( ) ;
}
2022-01-06 20:35:37 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kMXKAccountUserInfoDidChangeNotification object : self . mxCredentials . userId ] ;
2021-12-03 10:47:24 +00:00
}
failure : ^ ( NSError * error ) {
2022-01-06 20:35:37 +00:00
MXLogDebug ( @ "[MXKAccount] %@: set user presence (%lu) failed" , self . mxCredentials . userId , ( unsigned long ) self -> userPresence ) ;
2021-12-03 10:47:24 +00:00
} ] ;
}
else if ( hideUserPresence )
{
2022-01-06 20:35:37 +00:00
MXLogDebug ( @ "[MXKAccount] %@: set user presence is disabled." , self . mxCredentials . userId ) ;
2021-12-03 10:47:24 +00:00
}
}
# pragma mark -
/ * *
Create a matrix session based on the provided store .
When store data is ready , the live stream is automatically launched by synchronising the session with the server .
In case of failure during server sync , the method is reiterated until the data is up - to - date with the server .
This loop is stopped if you call [ MXCAccount closeSession : ] , it is suspended if you call [ MXCAccount pauseInBackgroundTask ] .
@ param store the store to use for the session .
* /
- ( void ) openSessionWithStore : ( id < MXStore > ) store
{
// Sanity check
2022-01-06 20:35:37 +00:00
if ( ! self . mxCredentials || ! mxRestClient )
2021-12-03 10:47:24 +00:00
{
MXLogDebug ( @ "[MXKAccount] Matrix session cannot be created without credentials" ) ;
return ;
}
// Close potential session ( keep associated store ) .
[ self closeSession : NO ] ;
openSessionStartDate = [ NSDate date ] ;
// Instantiate new session
mxSession = [ [ MXSession alloc ] initWithMatrixRestClient : mxRestClient ] ;
// Check whether an antivirus url is defined .
if ( _antivirusServerURL )
{
// Enable the antivirus scanner in the current session .
[ mxSession setAntivirusServerURL : _antivirusServerURL ] ;
}
// Set default MXEvent -> NSString formatter
MXKEventFormatter * eventFormatter = [ [ MXKEventFormatter alloc ] initWithMatrixSession : self . mxSession ] ;
eventFormatter . isForSubtitle = YES ;
// Apply the event types filter to display only the wanted event types .
eventFormatter . eventTypesFilterForMessages = [ MXKAppSettings standardAppSettings ] . eventsFilterForMessages ;
mxSession . roomSummaryUpdateDelegate = eventFormatter ;
// Observe UIApplicationSignificantTimeChangeNotification to refresh to MXRoomSummaries if date / time are shown .
// UIApplicationSignificantTimeChangeNotification is posted if DST is updated , carrier time is updated
UIApplicationSignificantTimeChangeNotificationObserver = [ [ NSNotificationCenter defaultCenter ] addObserverForName : UIApplicationSignificantTimeChangeNotification object : nil queue : [ NSOperationQueue mainQueue ] usingBlock : ^ ( NSNotification * notif ) {
[ self onDateTimeFormatUpdate ] ;
} ] ;
// Observe NSCurrentLocaleDidChangeNotification to refresh MXRoomSummaries if date / time are shown .
// NSCurrentLocaleDidChangeNotification is triggered when the time swicthes to AM / PM to 24 h time format
NSCurrentLocaleDidChangeNotificationObserver = [ [ NSNotificationCenter defaultCenter ] addObserverForName : NSCurrentLocaleDidChangeNotification object : nil queue : [ NSOperationQueue mainQueue ] usingBlock : ^ ( NSNotification * notif ) {
[ self onDateTimeFormatUpdate ] ;
} ] ;
// Force a date refresh for all the last messages .
[ self onDateTimeFormatUpdate ] ;
// Register session state observer
sessionStateObserver = [ [ NSNotificationCenter defaultCenter ] addObserverForName : kMXSessionStateDidChangeNotification object : nil queue : [ NSOperationQueue mainQueue ] usingBlock : ^ ( NSNotification * notif ) {
// Check whether the concerned session is the associated one
if ( notif . object = = self -> mxSession )
{
[ self onMatrixSessionStateChange ] ;
}
} ] ;
MXWeakify ( self ) ;
[ mxSession setStore : store success : ^ {
// Complete session registration by launching live stream
MXStrongifyAndReturnIfNil ( self ) ;
// Validate the availability of local contact sync for any changes to the
// authorization of contacts access that may have occurred since the last launch .
// The session is passed in as the contacts manager may not have had a session added yet .
[ MXKContactManager . sharedManager validateSyncLocalContactsStateForSession : self . mxSession ] ;
// Refresh pusher state
[ self refreshAPNSPusher ] ;
[ self refreshPushKitPusher ] ;
// Launch server sync
[ self launchInitialServerSync ] ;
} failure : ^ ( NSError * error ) {
// This cannot happen . Loading of MXFileStore cannot fail .
MXStrongifyAndReturnIfNil ( self ) ;
self -> mxSession = nil ;
[ [ NSNotificationCenter defaultCenter ] removeObserver : self -> sessionStateObserver ] ;
self -> sessionStateObserver = nil ;
} ] ;
}
/ * *
Close the matrix session .
@ param clearStore set YES to delete all store data .
* /
- ( void ) closeSession : ( BOOL ) clearStore
{
MXLogDebug ( @ "[MXKAccount] closeSession (%u)" , clearStore ) ;
if ( NSCurrentLocaleDidChangeNotificationObserver )
{
[ [ NSNotificationCenter defaultCenter ] removeObserver : NSCurrentLocaleDidChangeNotificationObserver ] ;
NSCurrentLocaleDidChangeNotificationObserver = nil ;
}
if ( UIApplicationSignificantTimeChangeNotificationObserver )
{
[ [ NSNotificationCenter defaultCenter ] removeObserver : UIApplicationSignificantTimeChangeNotificationObserver ] ;
UIApplicationSignificantTimeChangeNotificationObserver = nil ;
}
[ self removeNotificationListener ] ;
if ( reachabilityObserver )
{
[ [ NSNotificationCenter defaultCenter ] removeObserver : reachabilityObserver ] ;
reachabilityObserver = nil ;
}
if ( sessionStateObserver )
{
[ [ NSNotificationCenter defaultCenter ] removeObserver : sessionStateObserver ] ;
sessionStateObserver = nil ;
}
[ initialServerSyncTimer invalidate ] ;
initialServerSyncTimer = nil ;
if ( userUpdateListener )
{
[ mxSession . myUser removeListener : userUpdateListener ] ;
userUpdateListener = nil ;
}
if ( mxSession )
{
// Reset room data stored in memory
[ MXKRoomDataSourceManager removeSharedManagerForMatrixSession : mxSession ] ;
if ( clearStore )
{
// Force a reload of device keys at the next session start .
// This will fix potential UISIs other peoples receive for our messages .
[ mxSession . crypto resetDeviceKeys ] ;
// Clean other stores
[ mxSession . scanManager deleteAllAntivirusScans ] ;
[ mxSession . aggregations resetData ] ;
}
else
{
// For recomputing of room summaries as they are a cache of computed data
[ mxSession resetRoomsSummariesLastMessage ] ;
}
// Close session
[ mxSession close ] ;
if ( clearStore )
{
[ mxSession . store deleteAllData ] ;
}
mxSession = nil ;
}
notifyOpenSessionFailure = YES ;
}
- ( void ) logout : ( void ( ^ ) ( void ) ) completion
{
if ( ! mxSession )
{
MXLogDebug ( @ "[MXKAccount] logout: Need to open the closed session to make a logout request" ) ;
id < MXStore > store = [ [ [ MXKAccountManager sharedManager ] . storeClass alloc ] init ] ;
mxSession = [ [ MXSession alloc ] initWithMatrixRestClient : mxRestClient ] ;
MXWeakify ( self ) ;
[ mxSession setStore : store success : ^ {
MXStrongifyAndReturnIfNil ( self ) ;
[ self logout : completion ] ;
} failure : ^ ( NSError * error ) {
completion ( ) ;
} ] ;
return ;
}
[ self deletePusher ] ;
[ self enablePushKitNotifications : NO success : nil failure : nil ] ;
MXHTTPOperation * operation = [ mxSession logout : ^ {
[ self closeSession : YES ] ;
if ( completion )
{
completion ( ) ;
}
} failure : ^ ( NSError * error ) {
// Close the session even if the logout request failed
[ self closeSession : YES ] ;
if ( completion )
{
completion ( ) ;
}
} ] ;
// Do not retry on failure .
operation . maxNumberOfTries = 1 ;
}
// Logout locally , do not send server request
- ( void ) logoutLocally : ( void ( ^ ) ( void ) ) completion
{
[ self deletePusher ] ;
[ self enablePushKitNotifications : NO success : nil failure : nil ] ;
[ mxSession enableCrypto : NO success : ^ {
[ self closeSession : YES ] ;
if ( completion )
{
completion ( ) ;
}
} failure : ^ ( NSError * error ) {
// Close the session even if the logout request failed
[ self closeSession : YES ] ;
if ( completion )
{
completion ( ) ;
}
} ] ;
}
- ( void ) logoutSendingServerRequest : ( BOOL ) sendLogoutServerRequest
completion : ( void ( ^ ) ( void ) ) completion
{
if ( sendLogoutServerRequest )
{
[ self logout : completion ] ;
}
else
{
[ self logoutLocally : completion ] ;
}
}
# pragma mark - Soft logout
- ( void ) softLogout
{
_isSoftLogout = YES ;
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
// Stop SDK making requests to the homeserver
[ mxSession close ] ;
}
- ( void ) hydrateWithCredentials : ( MXCredentials * ) credentials
{
// Sanity check
2022-01-06 20:35:37 +00:00
if ( [ self . mxCredentials . userId isEqualToString : credentials . userId ] )
2021-12-03 10:47:24 +00:00
{
2022-01-06 20:35:37 +00:00
_mxCredentials = credentials ;
2021-12-03 10:47:24 +00:00
_isSoftLogout = NO ;
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
[ self prepareRESTClient ] ;
}
else
{
2022-01-06 20:35:37 +00:00
MXLogDebug ( @ "[MXKAccount] hydrateWithCredentials: Error: users ids mismatch: %@ vs %@" , credentials . userId , self . mxCredentials . userId ) ;
2021-12-03 10:47:24 +00:00
}
}
- ( void ) deletePusher
{
if ( self . pushNotificationServiceIsActive )
{
[ self enableAPNSPusher : NO success : nil failure : nil ] ;
}
}
- ( void ) pauseInBackgroundTask
{
// Reset internal flag
isPauseRequested = NO ;
if ( mxSession && mxSession . isPauseable )
{
id < MXBackgroundModeHandler > handler = [ MXSDKOptions sharedInstance ] . backgroundModeHandler ;
if ( handler )
{
if ( ! self . backgroundTask . isRunning )
{
self . backgroundTask = [ handler startBackgroundTaskWithName : @ "[MXKAccount] pauseInBackgroundTask" expirationHandler : nil ] ;
}
}
// Pause SDK
[ mxSession pause ] ;
// Update user presence
__weak typeof ( self ) weakSelf = self ;
[ self setUserPresence : MXPresenceUnavailable andStatusMessage : nil completion : ^ {
if ( weakSelf )
{
typeof ( self ) self = weakSelf ;
if ( self . backgroundTask . isRunning )
{
[ self . backgroundTask stop ] ;
self . backgroundTask = nil ;
}
}
} ] ;
}
else
{
// Cancel pending actions
[ [ NSNotificationCenter defaultCenter ] removeObserver : reachabilityObserver ] ;
reachabilityObserver = nil ;
[ initialServerSyncTimer invalidate ] ;
initialServerSyncTimer = nil ;
if ( mxSession . state = = MXSessionStateSyncInProgress || mxSession . state = = MXSessionStateInitialised || mxSession . state = = MXSessionStateStoreDataReady )
{
// Make sure the SDK finish its work before the app goes sleeping in background
id < MXBackgroundModeHandler > handler = [ MXSDKOptions sharedInstance ] . backgroundModeHandler ;
if ( handler )
{
if ( ! self . backgroundTask . isRunning )
{
self . backgroundTask = [ handler startBackgroundTaskWithName : @ "[MXKAccount] pauseInBackgroundTask" expirationHandler : nil ] ;
}
}
MXLogDebug ( @ "[MXKAccount] Pause is delayed at the end of sync (current state %tu)" , mxSession . state ) ;
isPauseRequested = YES ;
}
}
}
- ( void ) resume
{
isPauseRequested = NO ;
if ( mxSession )
{
MXLogVerbose ( @ "[MXKAccount] resume with session state: %tu" , mxSession . state ) ;
[ self cancelBackgroundSync ] ;
if ( mxSession . state = = MXSessionStatePaused || mxSession . state = = MXSessionStatePauseRequested )
{
// Resume SDK and update user presence
[ mxSession resume : ^ {
[ self setUserPresence : MXPresenceOnline andStatusMessage : nil completion : nil ] ;
[ self refreshAPNSPusher ] ;
[ self refreshPushKitPusher ] ;
} ] ;
}
else if ( mxSession . state = = MXSessionStateStoreDataReady || mxSession . state = = MXSessionStateInitialSyncFailed )
{
// The session initialisation was uncompleted , we try to complete it here .
[ self launchInitialServerSync ] ;
[ self refreshAPNSPusher ] ;
[ self refreshPushKitPusher ] ;
}
else if ( mxSession . state = = MXSessionStateSyncInProgress )
{
[ self refreshAPNSPusher ] ;
[ self refreshPushKitPusher ] ;
}
// Cancel background task
if ( self . backgroundTask . isRunning )
{
[ self . backgroundTask stop ] ;
self . backgroundTask = nil ;
}
}
}
- ( void ) reload : ( BOOL ) clearCache
{
// close potential session
[ self closeSession : clearCache ] ;
if ( ! _disabled )
{
// Open a new matrix session
id < MXStore > store = [ [ [ MXKAccountManager sharedManager ] . storeClass alloc ] init ] ;
[ self openSessionWithStore : store ] ;
}
}
# pragma mark - Push notifications
// Refresh the APNS pusher state for this account on this device .
- ( void ) refreshAPNSPusher
{
MXLogDebug ( @ "[MXKAccount][Push] refreshAPNSPusher" ) ;
// Check the conditions required to run the pusher
if ( self . pushNotificationServiceIsActive )
{
MXLogDebug ( @ "[MXKAccount][Push] refreshAPNSPusher: Refresh APNS pusher for %@ account" , self . mxCredentials . userId ) ;
// Create / restore the pusher
[ self enableAPNSPusher : YES
success : nil
failure : ^ ( NSError * error ) {
MXLogDebug ( @ "[MXKAccount][Push] ;: Error: %@" , error ) ;
} ] ;
}
else if ( _hasPusherForPushNotifications )
{
if ( [ MXKAccountManager sharedManager ] . apnsDeviceToken )
{
if ( mxSession )
{
// Turn off pusher if user denied remote notification .
MXLogDebug ( @ "[MXKAccount][Push] refreshAPNSPusher: Disable APNS pusher for %@ account (notifications are denied)" , self . mxCredentials . userId ) ;
[ self enableAPNSPusher : NO success : nil failure : nil ] ;
}
}
else
{
MXLogDebug ( @ "[MXKAccount][Push] refreshAPNSPusher: APNS pusher for %@ account is already disabled. Reset _hasPusherForPushNotifications" , self . mxCredentials . userId ) ;
_hasPusherForPushNotifications = NO ;
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
}
}
}
// Enable / Disable the APNS pusher for this account on this device on the homeserver .
- ( void ) enableAPNSPusher : ( BOOL ) enabled success : ( void ( ^ ) ( void ) ) success failure : ( void ( ^ ) ( NSError * ) ) failure
{
MXLogDebug ( @ "[MXKAccount][Push] enableAPNSPusher: %@" , @ ( enabled ) ) ;
# ifdef DEBUG
NSString * appId = [ [ NSUserDefaults standardUserDefaults ] objectForKey : @ "pusherAppIdDev" ] ;
# else
NSString * appId = [ [ NSUserDefaults standardUserDefaults ] objectForKey : @ "pusherAppIdProd" ] ;
# endif
NSString * locKey = MXKAppSettings . standardAppSettings . notificationBodyLocalizationKey ;
NSDictionary * pushData = @ {
@ "url" : self . pushGatewayURL ,
@ "format" : @ "event_id_only" ,
@ "default_payload" : @ { @ "aps" : @ { @ "mutable-content" : @ ( 1 ) , @ "alert" : @ { @ "loc-key" : locKey , @ "loc-args" : @ [ ] } } }
} ;
[ self enablePusher : enabled appId : appId token : [ MXKAccountManager sharedManager ] . apnsDeviceToken pushData : pushData success : ^ {
MXLogDebug ( @ "[MXKAccount][Push] enableAPNSPusher: Succeeded to update APNS pusher for %@ (%d)" , self . mxCredentials . userId , enabled ) ;
self -> _hasPusherForPushNotifications = enabled ;
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
if ( success )
{
success ( ) ;
}
2022-01-06 20:35:37 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kMXKAccountAPNSActivityDidChangeNotification object : self . mxCredentials . userId ] ;
2021-12-03 10:47:24 +00:00
} failure : ^ ( NSError * error ) {
// Ignore error if the client try to disable an unknown token
if ( ! enabled )
{
// Check whether the token was unknown
MXError * mxError = [ [ MXError alloc ] initWithNSError : error ] ;
if ( mxError && [ mxError . errcode isEqualToString : kMXErrCodeStringUnknown ] )
{
MXLogDebug ( @ "[MXKAccount][Push] enableAPNSPusher: APNS was already disabled for %@!" , self . mxCredentials . userId ) ;
// Ignore the error
if ( success )
{
success ( ) ;
}
2022-01-06 20:35:37 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kMXKAccountAPNSActivityDidChangeNotification object : self . mxCredentials . userId ] ;
2021-12-03 10:47:24 +00:00
return ;
}
MXLogDebug ( @ "[MXKAccount][Push] enableAPNSPusher: Failed to disable APNS %@! (%@)" , self . mxCredentials . userId , error ) ;
}
else
{
MXLogDebug ( @ "[MXKAccount][Push] enableAPNSPusher: Failed to send APNS token for %@! (%@)" , self . mxCredentials . userId , error ) ;
}
if ( failure )
{
failure ( error ) ;
}
2022-01-06 20:35:37 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kMXKAccountAPNSActivityDidChangeNotification object : self . mxCredentials . userId ] ;
2021-12-03 10:47:24 +00:00
} ] ;
}
// Refresh the PushKit pusher state for this account on this device .
- ( void ) refreshPushKitPusher
{
MXLogDebug ( @ "[MXKAccount][Push] refreshPushKitPusher" ) ;
// Check the conditions required to run the pusher
if ( ! [ MXKAppSettings standardAppSettings ] . allowPushKitPushers )
{
// Turn off pusher if PushKit pushers are not allowed
MXLogDebug ( @ "[MXKAccount][Push] refreshPushKitPusher: Disable PushKit pusher for %@ account (pushers are not allowed)" , self . mxCredentials . userId ) ;
[ self enablePushKitPusher : NO success : nil failure : nil ] ;
}
else if ( self . isPushKitNotificationActive )
{
MXLogDebug ( @ "[MXKAccount][Push] refreshPushKitPusher: Refresh PushKit pusher for %@ account" , self . mxCredentials . userId ) ;
// Create / restore the pusher
[ self enablePushKitPusher : YES
success : nil
failure : ^ ( NSError * error ) {
MXLogDebug ( @ "[MXKAccount][Push] refreshPushKitPusher: Error: %@" , error ) ;
} ] ;
}
2022-01-06 20:35:37 +00:00
else if ( self . hasPusherForPushKitNotifications )
2021-12-03 10:47:24 +00:00
{
if ( [ MXKAccountManager sharedManager ] . pushDeviceToken )
{
if ( mxSession )
{
// Turn off pusher if user denied remote notification .
MXLogDebug ( @ "[MXKAccount][Push] refreshPushKitPusher: Disable PushKit pusher for %@ account (notifications are denied)" , self . mxCredentials . userId ) ;
[ self enablePushKitPusher : NO success : nil failure : nil ] ;
}
}
else
{
MXLogDebug ( @ "[MXKAccount][Push] refreshPushKitPusher: PushKit pusher for %@ account is already disabled. Reset _hasPusherForPushKitNotifications" , self . mxCredentials . userId ) ;
2022-01-06 20:35:37 +00:00
self -> _hasPusherForPushKitNotifications = NO ;
2021-12-03 10:47:24 +00:00
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
}
}
}
// Enable / Disable the pusher based on PushKit for this account on this device on the homeserver .
- ( void ) enablePushKitPusher : ( BOOL ) enabled success : ( void ( ^ ) ( void ) ) success failure : ( void ( ^ ) ( NSError * ) ) failure
{
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitPusher: %@" , @ ( enabled ) ) ;
if ( enabled && ! [ MXKAppSettings standardAppSettings ] . allowPushKitPushers )
{
// sanity check , if accidently try to enable the pusher
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitPusher: Do not enable it because PushKit pushers not allowed" ) ;
if ( failure )
{
failure ( [ NSError errorWithDomain : kMXKAccountErrorDomain code : 0 userInfo : nil ] ) ;
}
return ;
}
NSString * appIdKey ;
# ifdef DEBUG
appIdKey = @ "pushKitAppIdDev" ;
# else
appIdKey = @ "pushKitAppIdProd" ;
# endif
NSString * appId = [ [ NSUserDefaults standardUserDefaults ] objectForKey : appIdKey ] ;
NSMutableDictionary * pushData = [ NSMutableDictionary dictionaryWithDictionary : @ { @ "url" : self . pushGatewayURL } ] ;
NSDictionary * options = [ MXKAccountManager sharedManager ] . pushOptions ;
if ( options . count )
{
[ pushData addEntriesFromDictionary : options ] ;
}
NSData * token = [ MXKAccountManager sharedManager ] . pushDeviceToken ;
if ( ! token )
{
// sanity check , if no token there is no point of calling the endpoint
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitPusher: Failed to update PushKit pusher to %@ for %@. (token is missing)" , @ ( enabled ) , self . mxCredentials . userId ) ;
if ( failure )
{
failure ( [ NSError errorWithDomain : kMXKAccountErrorDomain code : 0 userInfo : nil ] ) ;
}
return ;
}
[ self enablePusher : enabled appId : appId token : token pushData : pushData success : ^ {
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitPusher: Succeeded to update PushKit pusher for %@. Enabled: %@. Token: %@" , self . mxCredentials . userId , @ ( enabled ) , [ MXKTools logForPushToken : token ] ) ;
self -> _hasPusherForPushKitNotifications = enabled ;
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
if ( success )
{
success ( ) ;
}
2022-01-06 20:35:37 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kMXKAccountPushKitActivityDidChangeNotification object : self . mxCredentials . userId ] ;
2021-12-03 10:47:24 +00:00
} failure : ^ ( NSError * error ) {
// Ignore error if the client try to disable an unknown token
if ( ! enabled )
{
// Check whether the token was unknown
MXError * mxError = [ [ MXError alloc ] initWithNSError : error ] ;
if ( mxError && [ mxError . errcode isEqualToString : kMXErrCodeStringUnknown ] )
{
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitPusher: Push was already disabled for %@!" , self . mxCredentials . userId ) ;
// Ignore the error
if ( success )
{
success ( ) ;
}
2022-01-06 20:35:37 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kMXKAccountPushKitActivityDidChangeNotification object : self . mxCredentials . userId ] ;
2021-12-03 10:47:24 +00:00
return ;
}
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitPusher: Failed to disable Push %@! (%@)" , self . mxCredentials . userId , error ) ;
}
else
{
MXLogDebug ( @ "[MXKAccount][Push] enablePushKitPusher: Failed to send Push token for %@! (%@)" , self . mxCredentials . userId , error ) ;
}
if ( failure )
{
failure ( error ) ;
}
2022-01-06 20:35:37 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kMXKAccountPushKitActivityDidChangeNotification object : self . mxCredentials . userId ] ;
2021-12-03 10:47:24 +00:00
} ] ;
}
- ( void ) enablePusher : ( BOOL ) enabled appId : ( NSString * ) appId token : ( NSData * ) token pushData : ( NSDictionary * ) pushData success : ( void ( ^ ) ( void ) ) success failure : ( void ( ^ ) ( NSError * ) ) failure
{
MXLogDebug ( @ "[MXKAccount][Push] enablePusher: %@" , @ ( enabled ) ) ;
// Refuse to try & turn push on if we ' re not logged in , it ' s nonsensical .
2022-01-06 20:35:37 +00:00
if ( ! self . mxCredentials )
2021-12-03 10:47:24 +00:00
{
MXLogDebug ( @ "[MXKAccount][Push] enablePusher: Not setting push token because we're not logged in" ) ;
return ;
}
// Check whether the Push Gateway URL has been configured .
if ( ! self . pushGatewayURL )
{
MXLogDebug ( @ "[MXKAccount][Push] enablePusher: Not setting pusher because the Push Gateway URL is undefined" ) ;
return ;
}
if ( ! appId )
{
MXLogDebug ( @ "[MXKAccount][Push] enablePusher: Not setting pusher because pusher app id is undefined" ) ;
return ;
}
NSString * appDisplayName = [ NSString stringWithFormat : @ "%@ (iOS)" , [ [ NSBundle mainBundle ] objectForInfoDictionaryKey : @ "CFBundleDisplayName" ] ] ;
NSString * b64Token = [ token base64EncodedStringWithOptions : 0 ] ;
NSString * deviceLang = [ NSLocale preferredLanguages ] [ 0 ] ;
NSString * profileTag = [ [ NSUserDefaults standardUserDefaults ] valueForKey : @ "pusherProfileTag" ] ;
if ( ! profileTag )
{
profileTag = @ "" ;
NSString * alphabet = @ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" ;
for ( int i = 0 ; i < 16 ; + + i )
{
unsigned char c = [ alphabet characterAtIndex : arc4random ( ) % alphabet . length ] ;
profileTag = [ profileTag stringByAppendingFormat : @ "%c" , c ] ;
}
MXLogDebug ( @ "[MXKAccount][Push] enablePusher: Generated fresh profile tag: %@" , profileTag ) ;
[ [ NSUserDefaults standardUserDefaults ] setValue : profileTag forKey : @ "pusherProfileTag" ] ;
}
else
{
MXLogDebug ( @ "[MXKAccount][Push] enablePusher: Using existing profile tag: %@" , profileTag ) ;
}
NSObject * kind = enabled ? @ "http" : [ NSNull null ] ;
// Use the append flag to handle multiple accounts registration .
BOOL append = NO ;
// Check whether a pusher is running for another account
NSArray * activeAccounts = [ MXKAccountManager sharedManager ] . activeAccounts ;
for ( MXKAccount * account in activeAccounts )
{
if ( ! [ account . mxCredentials . userId isEqualToString : self . mxCredentials . userId ] && account . pushNotificationServiceIsActive )
{
append = YES ;
break ;
}
}
MXLogDebug ( @ "[MXKAccount][Push] enablePusher: append flag: %d" , append ) ;
MXRestClient * restCli = self . mxRestClient ;
[ restCli setPusherWithPushkey : b64Token kind : kind appId : appId appDisplayName : appDisplayName deviceDisplayName : [ [ UIDevice currentDevice ] name ] profileTag : profileTag lang : deviceLang data : pushData append : append success : success failure : failure ] ;
}
# pragma mark - InApp notifications
- ( void ) listenToNotifications : ( MXOnNotification ) onNotification
{
// Check conditions required to add notification listener
if ( ! mxSession || ! onNotification )
{
return ;
}
// Remove existing listener ( if any )
[ self removeNotificationListener ] ;
// Register on notification center
notificationCenterListener = [ self . mxSession . notificationCenter listenToNotifications : ^ ( MXEvent * event , MXRoomState * roomState , MXPushRule * rule )
{
// Apply first the event filter defined in the related room data source
MXKRoomDataSourceManager * roomDataSourceManager = [ MXKRoomDataSourceManager sharedManagerForMatrixSession : self -> mxSession ] ;
[ roomDataSourceManager roomDataSourceForRoom : event . roomId create : NO onComplete : ^ ( MXKRoomDataSource * roomDataSource ) {
if ( roomDataSource )
{
if ( ! roomDataSource . eventFormatter . eventTypesFilterForMessages || [ roomDataSource . eventFormatter . eventTypesFilterForMessages indexOfObject : event . type ] ! = NSNotFound )
{
// Check conditions to report this notification
if ( nil = = self -> ignoredRooms || [ self -> ignoredRooms indexOfObject : event . roomId ] = = NSNotFound )
{
onNotification ( event , roomState , rule ) ;
}
}
}
} ] ;
} ] ;
}
- ( void ) removeNotificationListener
{
if ( notificationCenterListener )
{
[ self . mxSession . notificationCenter removeListener : notificationCenterListener ] ;
notificationCenterListener = nil ;
}
ignoredRooms = nil ;
}
- ( void ) updateNotificationListenerForRoomId : ( NSString * ) roomID ignore : ( BOOL ) isIgnored
{
if ( isIgnored )
{
if ( ! ignoredRooms )
{
ignoredRooms = [ [ NSMutableArray alloc ] init ] ;
}
[ ignoredRooms addObject : roomID ] ;
}
else if ( ignoredRooms )
{
[ ignoredRooms removeObject : roomID ] ;
}
}
# pragma mark - Internals
- ( void ) launchInitialServerSync
{
// Complete the session registration when store data is ready .
// Cancel potential reachability observer and pending action
[ [ NSNotificationCenter defaultCenter ] removeObserver : reachabilityObserver ] ;
reachabilityObserver = nil ;
[ initialServerSyncTimer invalidate ] ;
initialServerSyncTimer = nil ;
// Sanity check
if ( ! mxSession || ( mxSession . state ! = MXSessionStateStoreDataReady && mxSession . state ! = MXSessionStateInitialSyncFailed ) )
{
MXLogDebug ( @ "[MXKAccount] Initial server sync is applicable only when store data is ready to complete session initialisation" ) ;
return ;
}
// Use / sync filter corresponding to current settings and homeserver capabilities
MXWeakify ( self ) ;
[ self buildSyncFilter : ^ ( MXFilterJSONModel * syncFilter ) {
MXStrongifyAndReturnIfNil ( self ) ;
// Make sure the filter is compatible with the previously used one
MXWeakify ( self ) ;
[ self checkSyncFilterCompatibility : syncFilter completion : ^ ( BOOL compatible ) {
MXStrongifyAndReturnIfNil ( self ) ;
if ( ! compatible )
{
// Else clear the cache
MXLogDebug ( @ "[MXKAccount] New /sync filter not compatible with previous one. Clear cache" ) ;
[ self reload : YES ] ;
return ;
}
// Launch mxSession
MXWeakify ( self ) ;
[ self . mxSession startWithSyncFilter : syncFilter onServerSyncDone : ^ {
MXStrongifyAndReturnIfNil ( self ) ;
2022-01-06 20:35:37 +00:00
MXLogDebug ( @ "[MXKAccount] %@: The session is ready. Matrix SDK session has been started in %0.fms." , self . mxCredentials . userId , [ [ NSDate date ] timeIntervalSinceDate : self -> openSessionStartDate ] * 1000 ) ;
2021-12-03 10:47:24 +00:00
[ self setUserPresence : MXPresenceOnline andStatusMessage : nil completion : nil ] ;
} failure : ^ ( NSError * error ) {
MXStrongifyAndReturnIfNil ( self ) ;
MXLogDebug ( @ "[MXKAccount] Initial Sync failed. Error: %@" , error ) ;
BOOL isClientTimeout = [ error . domain isEqualToString : NSURLErrorDomain ] && error . code = = NSURLErrorTimedOut ;
NSHTTPURLResponse * httpResponse = [ MXHTTPOperation urlResponseFromError : error ] ;
BOOL isServerTimeout = httpResponse && [ initialSyncSilentErrorsHTTPStatusCodes containsObject : @ ( httpResponse . statusCode ) ] ;
if ( isClientTimeout || isServerTimeout )
{
// do not propagate this error to the client
// the request will be retried or postponed according to the reachability status
MXLogDebug ( @ "[MXKAccount] Initial sync failure did not propagated" ) ;
}
else if ( self -> notifyOpenSessionFailure && error )
{
// Notify MatrixKit user only once
self -> notifyOpenSessionFailure = NO ;
NSString * myUserId = self . mxSession . myUser . userId ;
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kMXKErrorNotification object : error userInfo : myUserId ? @ { kMXKErrorUserIdKey : myUserId } : nil ] ;
}
// Check if it is a network connectivity issue
AFNetworkReachabilityManager * networkReachabilityManager = [ AFNetworkReachabilityManager sharedManager ] ;
MXLogDebug ( @ "[MXKAccount] Network reachability: %d" , networkReachabilityManager . isReachable ) ;
if ( networkReachabilityManager . isReachable )
{
// The problem is not the network
// Postpone a new attempt in 10 sec
self -> initialServerSyncTimer = [ NSTimer scheduledTimerWithTimeInterval : 10 target : self selector : @ selector ( launchInitialServerSync ) userInfo : self repeats : NO ] ;
}
else
{
// The device is not connected to the internet , wait for the connection to be up again before retrying
// Add observer to launch a new attempt according to reachability .
self -> reachabilityObserver = [ [ NSNotificationCenter defaultCenter ] addObserverForName : AFNetworkingReachabilityDidChangeNotification object : nil queue : [ NSOperationQueue mainQueue ] usingBlock : ^ ( NSNotification * note ) {
NSNumber * statusItem = note . userInfo [ AFNetworkingReachabilityNotificationStatusItem ] ;
if ( statusItem )
{
AFNetworkReachabilityStatus reachabilityStatus = statusItem . integerValue ;
if ( reachabilityStatus = = AFNetworkReachabilityStatusReachableViaWiFi || reachabilityStatus = = AFNetworkReachabilityStatusReachableViaWWAN )
{
// New attempt
[ self launchInitialServerSync ] ;
}
}
} ] ;
}
} ] ;
} ] ;
} ] ;
}
- ( void ) attemptDeviceDehydrationWithKeyData : ( NSData * ) keyData
success : ( void ( ^ ) ( void ) ) success
failure : ( void ( ^ ) ( NSError * error ) ) failure
{
[ self attemptDeviceDehydrationWithKeyData : keyData retry : YES success : success failure : failure ] ;
}
- ( void ) attemptDeviceDehydrationWithKeyData : ( NSData * ) keyData
retry : ( BOOL ) retry
success : ( void ( ^ ) ( void ) ) success
failure : ( void ( ^ ) ( NSError * error ) ) failure
{
if ( keyData = = nil )
{
MXLogWarning ( @ "[MXKAccount] attemptDeviceDehydrationWithRetry: no key provided for device dehydration" ) ;
if ( failure )
{
failure ( nil ) ;
}
return ;
}
MXLogDebug ( @ "[MXKAccount] attemptDeviceDehydrationWithRetry: starting device dehydration" ) ;
[ [ MXKAccountManager sharedManager ] . dehydrationService dehydrateDeviceWithMatrixRestClient : mxRestClient crypto : mxSession . crypto dehydrationKey : keyData success : ^ ( NSString * deviceId ) {
MXLogDebug ( @ "[MXKAccount] attemptDeviceDehydrationWithRetry: device successfully dehydrated" ) ;
if ( success )
{
success ( ) ;
}
} failure : ^ ( NSError * error ) {
if ( retry )
{
[ self attemptDeviceDehydrationWithKeyData : keyData retry : NO success : success failure : failure ] ;
MXLogError ( @ "[MXKAccount] attemptDeviceDehydrationWithRetry: device dehydration failed due to error: %@. Retrying." , error ) ;
}
else
{
MXLogError ( @ "[MXKAccount] attemptDeviceDehydrationWithRetry: device dehydration failed due to error: %@" , error ) ;
if ( failure )
{
failure ( error ) ;
}
}
} ] ;
}
- ( void ) onMatrixSessionStateChange
{
if ( mxSession . state = = MXSessionStateRunning )
{
// Check if pause has been requested
if ( isPauseRequested )
{
MXLogDebug ( @ "[MXKAccount] Apply the pending pause." ) ;
[ self pauseInBackgroundTask ] ;
return ;
}
// Check whether the session was not already running
if ( ! userUpdateListener )
{
// Register listener to user ' s information change
userUpdateListener = [ mxSession . myUser listenToUserUpdate : ^ ( MXEvent * event ) {
// Consider events related to user ' s presence
if ( event . eventType = = MXEventTypePresence )
{
self -> userPresence = [ MXTools presence : event . content [ @ "presence" ] ] ;
}
// Here displayname or other information have been updated , post update notification .
2022-01-06 20:35:37 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kMXKAccountUserInfoDidChangeNotification object : self . mxCredentials . userId ] ;
2021-12-03 10:47:24 +00:00
} ] ;
// User information are just up - to - date ( ` mxSession` is running ) , post update notification .
2022-01-06 20:35:37 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kMXKAccountUserInfoDidChangeNotification object : self . mxCredentials . userId ] ;
2021-12-03 10:47:24 +00:00
}
}
else if ( mxSession . state = = MXSessionStateStoreDataReady || mxSession . state = = MXSessionStateSyncInProgress )
{
// Remove listener ( if any ) , this action is required to handle correctly matrix sdk handler reload ( see clear cache )
if ( userUpdateListener )
{
[ mxSession . myUser removeListener : userUpdateListener ] ;
userUpdateListener = nil ;
}
else
{
// Here the initial server sync is in progress . The session is not running yet , but some user ' s information are available ( from local storage ) .
// We post update notification to let observer take into account this user ' s information even if they may not be up - to - date .
2022-01-06 20:35:37 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kMXKAccountUserInfoDidChangeNotification object : self . mxCredentials . userId ] ;
2021-12-03 10:47:24 +00:00
}
}
else if ( mxSession . state = = MXSessionStatePaused )
{
isPauseRequested = NO ;
}
}
- ( void ) prepareRESTClient
{
2022-01-06 20:35:37 +00:00
if ( ! self . mxCredentials )
2021-12-03 10:47:24 +00:00
{
return ;
}
2022-01-10 21:38:24 +00:00
MXWeakify ( self ) ;
2022-01-06 20:35:37 +00:00
mxRestClient = [ [ MXRestClient alloc ] initWithCredentials : self . mxCredentials andOnUnrecognizedCertificateBlock : ^ BOOL ( NSData * certificate ) {
2022-01-10 21:38:24 +00:00
MXStrongifyAndReturnValueIfNil ( self , NO ) ;
2021-12-03 10:47:24 +00:00
if ( _onCertificateChangeBlock )
{
if ( _onCertificateChangeBlock ( self , certificate ) )
{
// Update the certificate in credentials
2022-01-06 20:35:37 +00:00
self . mxCredentials . allowedCertificate = certificate ;
2021-12-03 10:47:24 +00:00
// Archive updated field
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
return YES ;
}
2022-01-06 20:35:37 +00:00
self . mxCredentials . ignoredCertificate = certificate ;
2021-12-03 10:47:24 +00:00
// Archive updated field
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
}
return NO ;
2022-01-06 20:35:37 +00:00
} andPersistentTokenDataHandler : ^ ( void ( ^ handler ) ( NSArray < MXCredentials * > * credentials , void ( ^ completion ) ( BOOL didUpdateCredentials ) ) ) {
[ MXKAccountManager . sharedManager readAndWriteCredentials : handler ] ;
2022-01-13 17:33:51 +00:00
} andUnauthenticatedHandler : ^ ( MXError * error , BOOL isSoftLogout , BOOL isRefreshTokenAuth , void ( ^ completion ) ( void ) ) {
2022-01-10 21:38:24 +00:00
MXStrongifyAndReturnIfNil ( self ) ;
2022-01-13 17:33:51 +00:00
[ self handleUnauthenticatedWithError : error isSoftLogout : isSoftLogout isRefreshTokenAuth : isRefreshTokenAuth andCompletion : completion ] ;
2021-12-03 10:47:24 +00:00
} ] ;
}
2022-01-13 17:33:51 +00:00
- ( void ) handleUnauthenticatedWithError : ( MXError * ) error isSoftLogout : ( BOOL ) isSoftLogout isRefreshTokenAuth : ( BOOL ) isRefreshTokenAuth andCompletion : ( void ( ^ ) ( void ) ) completion
2022-01-10 21:38:24 +00:00
{
2022-01-13 17:33:51 +00:00
[ Analytics . shared trackAuthUnauthenticatedErrorWithSoftLogout : isSoftLogout refreshTokenAuth : isRefreshTokenAuth errorCode : error . errcode errorReason : error . error ] ;
MXLogDebug ( @ "[MXKAccountManager] handleUnauthenticated: trackAuthUnauthenticatedErrorWithSoftLogout sent" ) ;
if ( isSoftLogout )
2022-01-10 21:38:24 +00:00
{
MXLogDebug ( @ "[MXKAccountManager] handleUnauthenticated: soft logout." ) ;
[ [ MXKAccountManager sharedManager ] softLogout : self ] ;
completion ( ) ;
}
else
{
MXLogDebug ( @ "[MXKAccountManager] handleUnauthenticated: hard logout." ) ;
[ [ MXKAccountManager sharedManager ] removeAccount : self sendLogoutRequest : NO completion : completion ] ;
}
}
2021-12-03 10:47:24 +00:00
- ( void ) onDateTimeFormatUpdate
{
if ( [ mxSession . roomSummaryUpdateDelegate isKindOfClass : MXKEventFormatter . class ] )
{
MXKEventFormatter * eventFormatter = ( MXKEventFormatter * ) mxSession . roomSummaryUpdateDelegate ;
// Update the date and time formatters
[ eventFormatter initDateTimeFormatters ] ;
dispatch_group _t dispatchGroup = dispatch_group _create ( ) ;
2021-12-29 14:40:09 +00:00
for ( MXRoom * room in mxSession . rooms )
2021-12-03 10:47:24 +00:00
{
2021-12-29 14:40:09 +00:00
MXRoomSummary * summary = room . summary ;
if ( summary )
{
dispatch_group _enter ( dispatchGroup ) ;
[ summary . mxSession eventWithEventId : summary . lastMessage . eventId
inRoom : summary . roomId
success : ^ ( MXEvent * event ) {
if ( event )
2021-12-03 10:47:24 +00:00
{
2021-12-29 14:40:09 +00:00
if ( summary . lastMessage . others = = nil )
{
summary . lastMessage . others = [ NSMutableDictionary dictionary ] ;
}
summary . lastMessage . others [ @ "lastEventDate" ] = [ eventFormatter dateStringFromEvent : event withTime : YES ] ;
2022-01-07 15:30:30 +00:00
[ self -> mxSession . store . roomSummaryStore storeSummary : summary ] ;
2021-12-03 10:47:24 +00:00
}
2021-12-29 14:40:09 +00:00
dispatch_group _leave ( dispatchGroup ) ;
} failure : ^ ( NSError * error ) {
2022-02-03 14:52:48 +00:00
MXLogError ( @ "[MXKAccount] onDateTimeFormatUpdate: event fetch failed: %@" , error ) ;
2021-12-29 14:40:09 +00:00
dispatch_group _leave ( dispatchGroup ) ;
} ] ;
}
2021-12-03 10:47:24 +00:00
}
dispatch_group _notify ( dispatchGroup , dispatch_get _main _queue ( ) , ^ {
// Commit store changes done
if ( [ self -> mxSession . store respondsToSelector : @ selector ( commit ) ] )
{
[ self -> mxSession . store commit ] ;
}
// Broadcast the change which concerns all the room summaries .
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kMXRoomSummaryDidChangeNotification object : nil userInfo : nil ] ;
} ) ;
}
}
# pragma mark - Crypto
- ( void ) resetDeviceId
{
2022-01-06 20:35:37 +00:00
self . mxCredentials . deviceId = nil ;
2021-12-03 10:47:24 +00:00
// Archive updated field
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
}
# pragma mark - backgroundSync management
- ( void ) cancelBackgroundSync
{
if ( self . backgroundSyncBgTask . isRunning )
{
MXLogDebug ( @ "[MXKAccount] The background Sync is cancelled." ) ;
if ( mxSession )
{
if ( mxSession . state = = MXSessionStateBackgroundSyncInProgress )
{
[ mxSession pause ] ;
}
}
[ self onBackgroundSyncDone : [ NSError errorWithDomain : kMXKAccountErrorDomain code : 0 userInfo : nil ] ] ;
}
}
- ( void ) onBackgroundSyncDone : ( NSError * ) error
{
if ( backgroundSyncTimer )
{
[ backgroundSyncTimer invalidate ] ;
backgroundSyncTimer = nil ;
}
if ( backgroundSyncFails && error )
{
backgroundSyncFails ( error ) ;
}
if ( backgroundSyncDone && ! error )
{
backgroundSyncDone ( ) ;
}
backgroundSyncDone = nil ;
backgroundSyncFails = nil ;
// End background task
if ( self . backgroundSyncBgTask . isRunning )
{
[ self . backgroundSyncBgTask stop ] ;
self . backgroundSyncBgTask = nil ;
}
}
- ( void ) onBackgroundSyncTimerOut
{
[ self cancelBackgroundSync ] ;
}
- ( void ) backgroundSync : ( unsigned int ) timeout success : ( void ( ^ ) ( void ) ) success failure : ( void ( ^ ) ( NSError * ) ) failure
{
// Check whether a background mode handler has been set .
id < MXBackgroundModeHandler > handler = [ MXSDKOptions sharedInstance ] . backgroundModeHandler ;
if ( handler )
{
// Only work when the application is suspended .
// Check conditions before launching background sync
if ( mxSession && mxSession . state = = MXSessionStatePaused )
{
MXLogDebug ( @ "[MXKAccount] starts a background Sync" ) ;
backgroundSyncDone = success ;
backgroundSyncFails = failure ;
MXWeakify ( self ) ;
self . backgroundSyncBgTask = [ handler startBackgroundTaskWithName : @ "[MXKAccount] backgroundSync:success:failure:" expirationHandler : ^ {
MXStrongifyAndReturnIfNil ( self ) ;
MXLogDebug ( @ "[MXKAccount] the background Sync fails because of the bg task timeout" ) ;
[ self cancelBackgroundSync ] ;
} ] ;
// ensure that the backgroundSync will be really done in the expected time
// the request could be done but the treatment could be long so add a timer to cancel it
// if it takes too much time
backgroundSyncTimer = [ [ NSTimer alloc ] initWithFireDate : [ NSDate dateWithTimeIntervalSinceNow : ( timeout - 1 ) / 1000 ]
interval : 0
target : self
selector : @ selector ( onBackgroundSyncTimerOut )
userInfo : nil
repeats : NO ] ;
[ [ NSRunLoop mainRunLoop ] addTimer : backgroundSyncTimer forMode : NSDefaultRunLoopMode ] ;
[ mxSession backgroundSync : timeout success : ^ {
MXLogDebug ( @ "[MXKAccount] the background Sync succeeds" ) ;
[ self onBackgroundSyncDone : nil ] ;
}
failure : ^ ( NSError * error ) {
MXLogDebug ( @ "[MXKAccount] the background Sync fails" ) ;
[ self onBackgroundSyncDone : error ] ;
}
] ;
}
else
{
MXLogDebug ( @ "[MXKAccount] cannot start background Sync (invalid state %tu)" , mxSession . state ) ;
failure ( [ NSError errorWithDomain : kMXKAccountErrorDomain code : 0 userInfo : nil ] ) ;
}
}
else
{
MXLogDebug ( @ "[MXKAccount] cannot start background Sync" ) ;
failure ( [ NSError errorWithDomain : kMXKAccountErrorDomain code : 0 userInfo : nil ] ) ;
}
}
# pragma mark - Sync filter
- ( void ) supportLazyLoadOfRoomMembers : ( void ( ^ ) ( BOOL supportLazyLoadOfRoomMembers ) ) completion
{
void ( ^ onUnsupportedLazyLoadOfRoomMembers ) ( NSError * ) = ^ ( NSError * error ) {
completion ( NO ) ;
} ;
// Check if the server supports LL sync filter
MXFilterJSONModel * filter = [ self syncFilterWithLazyLoadOfRoomMembers : YES ] ;
[ mxSession . store filterIdForFilter : filter success : ^ ( NSString * _Nullable filterId ) {
if ( filterId )
{
// The LL filter is already in the store . The HS supports LL
completion ( YES ) ;
}
else
{
// Check the Matrix versions supported by the HS
[ self . mxSession supportedMatrixVersions : ^ ( MXMatrixVersions * matrixVersions ) {
if ( matrixVersions . supportLazyLoadMembers )
{
// The HS supports LL
completion ( YES ) ;
}
else
{
onUnsupportedLazyLoadOfRoomMembers ( nil ) ;
}
} failure : onUnsupportedLazyLoadOfRoomMembers ] ;
}
} failure : onUnsupportedLazyLoadOfRoomMembers ] ;
}
/ * *
Build the sync filter according to application settings and HS capability .
@ param completion the block providing the sync filter to use .
* /
- ( void ) buildSyncFilter : ( void ( ^ ) ( MXFilterJSONModel * syncFilter ) ) completion
{
// Check settings
BOOL syncWithLazyLoadOfRoomMembersSetting = [ MXKAppSettings standardAppSettings ] . syncWithLazyLoadOfRoomMembers ;
if ( syncWithLazyLoadOfRoomMembersSetting )
{
// Check if the server supports LL sync filter before enabling it
[ self supportLazyLoadOfRoomMembers : ^ ( BOOL supportLazyLoadOfRoomMembers ) {
if ( supportLazyLoadOfRoomMembers )
{
completion ( [ self syncFilterWithLazyLoadOfRoomMembers : YES ] ) ;
}
else
{
// No support from the HS
// Disable the setting . That will avoid to make a request at every startup
[ MXKAppSettings standardAppSettings ] . syncWithLazyLoadOfRoomMembers = NO ;
completion ( [ self syncFilterWithLazyLoadOfRoomMembers : NO ] ) ;
}
} ] ;
}
else
{
completion ( [ self syncFilterWithLazyLoadOfRoomMembers : NO ] ) ;
}
}
/ * *
Compute the sync filter to use according to the device screen size .
@ param syncWithLazyLoadOfRoomMembers enable LL support .
@ return the sync filter to use .
* /
- ( MXFilterJSONModel * ) syncFilterWithLazyLoadOfRoomMembers : ( BOOL ) syncWithLazyLoadOfRoomMembers
{
MXFilterJSONModel * syncFilter ;
NSUInteger limit = 10 ;
// Define a message limit for / sync requests that is high enough so that
// a full page of room messages can be displayed without an additional
// server request .
// This limit value depends on the device screen size . So , the rough rule is :
// - use 10 for small phones ( 5 S / SE )
// - use 15 for phones ( 6 / 6 S / 7 / 8 )
// - use 20 for phablets ( . Plus / X / XR / XS / XSMax )
// - use 30 for iPads
UIUserInterfaceIdiom userInterfaceIdiom = [ [ UIDevice currentDevice ] userInterfaceIdiom ] ;
if ( userInterfaceIdiom = = UIUserInterfaceIdiomPhone )
{
CGFloat screenHeight = [ [ UIScreen mainScreen ] nativeBounds ] . size . height ;
if ( screenHeight = = 1334 ) // 6 / 6 S / 7 / 8 screen height
{
limit = 15 ;
}
else if ( screenHeight > 1334 )
{
limit = 20 ;
}
}
else if ( userInterfaceIdiom = = UIUserInterfaceIdiomPad )
{
limit = 30 ;
}
// Set that limit in the filter
if ( syncWithLazyLoadOfRoomMembers )
{
syncFilter = [ MXFilterJSONModel syncFilterForLazyLoadingWithMessageLimit : limit ] ;
}
else
{
syncFilter = [ MXFilterJSONModel syncFilterWithMessageLimit : limit ] ;
}
// TODO : We could extend the filter to match other settings ( self . showAllEventsInRoomHistory ,
// self . eventsFilterForMessages , etc ) .
return syncFilter ;
}
/ * *
Check the sync filter we want to use is compatible with the one previously used .
@ param syncFilter the sync filter to use .
@ param completion the block called to indicated the compatibility .
* /
- ( void ) checkSyncFilterCompatibility : ( MXFilterJSONModel * ) syncFilter completion : ( void ( ^ ) ( BOOL compatible ) ) completion
{
// There is no compatibility issue if no / sync was done before
if ( ! mxSession . store . eventStreamToken )
{
completion ( YES ) ;
}
// Check the filter we want to use is compatible with the one previously used
else if ( ! syncFilter && ! mxSession . syncFilterId )
{
// A nil filter implies a nil mxSession . syncFilterId . So , there is no filter change
completion ( YES ) ;
}
else if ( ! syncFilter || ! mxSession . syncFilterId )
{
// Change from no filter with using a filter or vice - versa . So , there is a filter change
MXLogDebug ( @ "[MXKAccount] checkSyncFilterCompatibility: Incompatible filter. New or old is nil. mxSession.syncFilterId: %@ - syncFilter: %@" ,
mxSession . syncFilterId , syncFilter . JSONDictionary ) ;
completion ( NO ) ;
}
else
{
// Check the filter is the one previously set
// It must be already in the store
MXWeakify ( self ) ;
[ mxSession . store filterIdForFilter : syncFilter success : ^ ( NSString * _Nullable filterId ) {
MXStrongifyAndReturnIfNil ( self ) ;
// Note : We could be more tolerant here
// We could accept filter hot change if the change is limited to the ` limit` filter value
// But we do not have this requirement yet
BOOL compatible = [ filterId isEqualToString : self . mxSession . syncFilterId ] ;
if ( ! compatible )
{
MXLogDebug ( @ "[MXKAccount] checkSyncFilterCompatibility: Incompatible filter ids. mxSession.syncFilterId: %@ - store.filterId: %@ - syncFilter: %@" ,
self . mxSession . syncFilterId , filterId , syncFilter . JSONDictionary ) ;
}
completion ( compatible ) ;
} failure : ^ ( NSError * _Nullable error ) {
// Should never happen
completion ( NO ) ;
} ] ;
}
}
# pragma mark - Identity server updates
- ( void ) registerAccountDataDidChangeIdentityServerNotification
{
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( handleAccountDataDidChangeIdentityServerNotification : ) name : kMXSessionAccountDataDidChangeIdentityServerNotification object : nil ] ;
}
- ( void ) handleAccountDataDidChangeIdentityServerNotification : ( NSNotification * ) notification
{
MXSession * mxSession = notification . object ;
if ( mxSession = = self . mxSession )
{
2022-01-06 20:35:37 +00:00
if ( ! [ self . mxCredentials . identityServer isEqualToString : self . mxSession . accountDataIdentityServer ] )
2021-12-03 10:47:24 +00:00
{
_identityServerURL = self . mxSession . accountDataIdentityServer ;
2022-01-06 20:35:37 +00:00
self . mxCredentials . identityServer = _identityServerURL ;
self . mxCredentials . identityServerAccessToken = nil ;
2021-12-03 10:47:24 +00:00
// Archive updated field
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
}
}
}
# pragma mark - Identity server Access Token updates
- ( void ) identityService : ( MXIdentityService * ) identityService didUpdateAccessToken : ( NSString * ) accessToken
{
2022-01-06 20:35:37 +00:00
self . mxCredentials . identityServerAccessToken = accessToken ;
2021-12-03 10:47:24 +00:00
}
- ( void ) registerIdentityServiceDidChangeAccessTokenNotification
{
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( handleIdentityServiceDidChangeAccessTokenNotification : ) name : MXIdentityServiceDidChangeAccessTokenNotification object : nil ] ;
}
- ( void ) handleIdentityServiceDidChangeAccessTokenNotification : ( NSNotification * ) notification
{
NSDictionary * userInfo = notification . userInfo ;
NSString * userId = userInfo [ MXIdentityServiceNotificationUserIdKey ] ;
NSString * identityServer = userInfo [ MXIdentityServiceNotificationIdentityServerKey ] ;
NSString * accessToken = userInfo [ MXIdentityServiceNotificationAccessTokenKey ] ;
2022-01-06 20:35:37 +00:00
if ( userId && identityServer && accessToken && [ self . mxCredentials . identityServer isEqualToString : identityServer ] )
2021-12-03 10:47:24 +00:00
{
2022-01-06 20:35:37 +00:00
self . mxCredentials . identityServerAccessToken = accessToken ;
2021-12-03 10:47:24 +00:00
// Archive updated field
[ [ MXKAccountManager sharedManager ] saveAccounts ] ;
}
}
@ end