123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794 |
- /**
- * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
- #import "NCDatabaseManager.h"
- #import "ABContact.h"
- #import "NCAppBranding.h"
- #import "NCChatBlock.h"
- #import "NCChatMessage.h"
- #import "NCContact.h"
- #import "NCRoom.h"
- #import "NextcloudTalk-Swift.h"
- NSString *const kTalkDatabaseFolder = @"Library/Application Support/Talk";
- NSString *const kTalkDatabaseFileName = @"talk.realm";
- uint64_t const kTalkDatabaseSchemaVersion = 69;
- NSString * const kCapabilitySystemMessages = @"system-messages";
- NSString * const kCapabilityNotificationLevels = @"notification-levels";
- NSString * const kCapabilityInviteGroupsAndMails = @"invite-groups-and-mails";
- NSString * const kCapabilityLockedOneToOneRooms = @"locked-one-to-one-rooms";
- NSString * const kCapabilityWebinaryLobby = @"webinary-lobby";
- NSString * const kCapabilityChatReadMarker = @"chat-read-marker";
- NSString * const kCapabilityStartCallFlag = @"start-call-flag";
- NSString * const kCapabilityCirclesSupport = @"circles-support";
- NSString * const kCapabilityChatReferenceId = @"chat-reference-id";
- NSString * const kCapabilityPhonebookSearch = @"phonebook-search";
- NSString * const kCapabilityChatReadStatus = @"chat-read-status";
- NSString * const kCapabilityReadOnlyRooms = @"read-only-rooms";
- NSString * const kCapabilityListableRooms = @"listable-rooms";
- NSString * const kCapabilityDeleteMessages = @"delete-messages";
- NSString * const kCapabilityCallFlags = @"conversation-call-flags";
- NSString * const kCapabilityRoomDescription = @"room-description";
- NSString * const kCapabilityTempUserAvatarAPI = @"temp-user-avatar-api";
- NSString * const kCapabilityLocationSharing = @"geo-location-sharing";
- NSString * const kCapabilityConversationV4 = @"conversation-v4";
- NSString * const kCapabilitySIPSupport = @"sip-support";
- NSString * const kCapabilitySIPSupportNoPIN = @"sip-support-nopin";
- NSString * const kCapabilityVoiceMessage = @"voice-message-sharing";
- NSString * const kCapabilitySignalingV3 = @"signaling-v3";
- NSString * const kCapabilityClearHistory = @"clear-history";
- NSString * const kCapabilityDirectMentionFlag = @"direct-mention-flag";
- NSString * const kCapabilityNotificationCalls = @"notification-calls";
- NSString * const kCapabilityConversationPermissions = @"conversation-permissions";
- NSString * const kCapabilityChatUnread = @"chat-unread";
- NSString * const kCapabilityReactions = @"reactions";
- NSString * const kCapabilityRichObjectListMedia = @"rich-object-list-media";
- NSString * const kCapabilityRichObjectDelete = @"rich-object-delete";
- NSString * const kCapabilityUnifiedSearch = @"unified-search";
- NSString * const kCapabilityChatPermission = @"chat-permission";
- NSString * const kCapabilityMessageExpiration = @"message-expiration";
- NSString * const kCapabilitySilentSend = @"silent-send";
- NSString * const kCapabilitySilentCall = @"silent-call";
- NSString * const kCapabilitySendCallNotification = @"send-call-notification";
- NSString * const kCapabilityTalkPolls = @"talk-polls";
- NSString * const kCapabilityRaiseHand = @"raise-hand";
- NSString * const kCapabilityRecordingV1 = @"recording-v1";
- NSString * const kCapabilitySingleConvStatus = @"single-conversation-status";
- NSString * const kCapabilityChatKeepNotifications = @"chat-keep-notifications";
- NSString * const kCapabilityConversationAvatars = @"avatar";
- NSString * const kCapabilityTypingIndicators = @"typing-privacy";
- NSString * const kCapabilityPublishingPermissions = @"publishing-permissions";
- NSString * const kCapabilityRemindMeLater = @"remind-me-later";
- NSString * const kCapabilityMarkdownMessages = @"markdown-messages";
- NSString * const kCapabilityNoteToSelf = @"note-to-self";
- NSString * const kCapabilityMediaCaption = @"media-caption";
- NSString * const kCapabilityEditMessages = @"edit-messages";
- NSString * const kCapabilityDeleteMessagesUnlimited = @"delete-messages-unlimited";
- NSString * const kCapabilityFederationV1 = @"federation-v1";
- NSString * const kCapabilityFederationV2 = @"federation-v2";
- NSString * const kCapabilityChatReadLast = @"chat-read-last";
- NSString * const kCapabilityBanV1 = @"ban-v1";
- NSString * const kCapabilityMentionPermissions = @"mention-permissions";
- NSString * const kCapabilityEditMessagesNoteToSelf = @"edit-messages-note-to-self";
- NSString * const kNotificationsCapabilityExists = @"exists";
- NSString * const kMinimumRequiredTalkCapability = kCapabilitySystemMessages; // Talk 4.0 is the minimum required version
- NSString * const NCDatabaseManagerPendingFederationInvitationsDidChange = @"NCDatabaseManagerPendingFederationInvitationsDidChange";
- NSString * const NCDatabaseManagerRoomCapabilitiesChangedNotification = @"NCDatabaseManagerRoomCapabilitiesChangedNotification";
- @implementation NCTranslation
- @end
- @interface NCDatabaseManager ()
- @property (nonatomic, strong) NSCache<NSString *, ServerCapabilities*> *capabilitiesCache;
- @end
- @implementation NCDatabaseManager
- + (NCDatabaseManager *)sharedInstance
- {
- static dispatch_once_t once;
- static NCDatabaseManager *sharedInstance;
- dispatch_once(&once, ^{
- sharedInstance = [[self alloc] init];
- });
- return sharedInstance;
- }
- - (id)init
- {
- self = [super init];
- if (self) {
- // Create Talk database directory
- NSString *path = [[[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:groupIdentifier] URLByAppendingPathComponent:kTalkDatabaseFolder] path];
- if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
- [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
- }
- [[NSFileManager defaultManager] setAttributes:@{NSFileProtectionKey:NSFileProtectionNone} ofItemAtPath:path error:nil];
- // Set Realm configuration
- RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration];
- NSURL *databaseURL = [[NSURL fileURLWithPath:path] URLByAppendingPathComponent:kTalkDatabaseFileName];
- configuration.fileURL = databaseURL;
- configuration.schemaVersion = kTalkDatabaseSchemaVersion;
- configuration.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
- // At the very minimum we need to update the version with an empty block to indicate that the schema has been upgraded (automatically) by Realm
- };
- // Tell Realm to use this new configuration object for the default Realm
- [RLMRealmConfiguration setDefaultConfiguration:configuration];
- // Now that we've told Realm how to handle the schema change, opening the file
- // will automatically perform the migration
- [RLMRealm defaultRealm];
- #ifdef DEBUG
- // Copy Talk DB to Documents directory
- NSString *dbCopyPath = [NSString stringWithFormat:@"%@/%@", NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0], kTalkDatabaseFileName];
- NSURL *dbCopyURL = [NSURL fileURLWithPath:dbCopyPath];
- [[NSFileManager defaultManager] removeItemAtURL:dbCopyURL error:nil];
- [[NSFileManager defaultManager] copyItemAtURL:databaseURL toURL:dbCopyURL error:nil];
- #endif
- self.capabilitiesCache = [[NSCache alloc] init];
- }
- return self;
- }
- #pragma mark - Talk accounts
- - (NSInteger)numberOfAccounts
- {
- return [TalkAccount allObjects].count;
- }
- - (TalkAccount *)activeAccount
- {
- TalkAccount *managedActiveAccount = [TalkAccount objectsWhere:(@"active = true")].firstObject;
- if (managedActiveAccount) {
- return [[TalkAccount alloc] initWithValue:managedActiveAccount];
- }
- return nil;
- }
- - (NSArray *)allAccounts
- {
- NSMutableArray *allAccounts = [NSMutableArray new];
- for (TalkAccount *managedAccount in [TalkAccount allObjects]) {
- TalkAccount *account = [[TalkAccount alloc] initWithValue:managedAccount];
- [allAccounts addObject:account];
- }
- return allAccounts;
- }
- - (NSArray *)inactiveAccounts
- {
- NSMutableArray *inactiveAccounts = [NSMutableArray new];
- for (TalkAccount *managedInactiveAccount in [TalkAccount objectsWhere:(@"active = false")]) {
- TalkAccount *inactiveAccount = [[TalkAccount alloc] initWithValue:managedInactiveAccount];
- [inactiveAccounts addObject:inactiveAccount];
- }
- return inactiveAccounts;
- }
- - (TalkAccount *)talkAccountForAccountId:(NSString *)accountId
- {
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@", accountId];
- TalkAccount *managedAccount = [TalkAccount objectsWithPredicate:query].firstObject;
- if (managedAccount) {
- return [[TalkAccount alloc] initWithValue:managedAccount];
- }
- return nil;
- }
- - (TalkAccount *)talkAccountForUserId:(NSString *)userId inServer:(NSString *)server
- {
- NSPredicate *query = [NSPredicate predicateWithFormat:@"userId = %@ AND server = %@", userId, server];
- TalkAccount *managedAccount = [TalkAccount objectsWithPredicate:query].firstObject;
- if (managedAccount) {
- return [[TalkAccount alloc] initWithValue:managedAccount];
- }
- return nil;
- }
- - (void)setActiveAccountWithAccountId:(NSString *)accountId
- {
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm beginWriteTransaction];
- for (TalkAccount *account in [TalkAccount allObjects]) {
- account.active = NO;
- }
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@", accountId];
- TalkAccount *activeAccount = [TalkAccount objectsWithPredicate:query].firstObject;
- activeAccount.active = YES;
- [realm commitWriteTransaction];
- }
- - (NSString *)accountIdForUser:(NSString *)user inServer:(NSString *)server
- {
- return [NSString stringWithFormat:@"%@@%@", user, server];
- }
- - (void)createAccountForUser:(NSString *)user inServer:(NSString *)server
- {
- TalkAccount *account = [[TalkAccount alloc] init];
- NSString *accountId = [self accountIdForUser:user inServer:server];
- account.accountId = accountId;
- account.server = server;
- account.user = user;
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm transactionWithBlock:^{
- [realm addObject:account];
- }];
- }
- - (void)removeAccountWithAccountId:(NSString *)accountId
- {
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm beginWriteTransaction];
- BOOL isLastAccount = [self numberOfAccounts] == 1;
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@", accountId];
- TalkAccount *removeAccount = [TalkAccount objectsWithPredicate:query].firstObject;
- if (removeAccount) {
- [realm deleteObject:removeAccount];
- }
- ServerCapabilities *serverCapabilities = [ServerCapabilities objectsWithPredicate:query].firstObject;
- if (serverCapabilities) {
- [realm deleteObject:serverCapabilities];
- [_capabilitiesCache removeObjectForKey:accountId];
- }
- [realm deleteObjects:[NCRoom objectsWithPredicate:query]];
- [realm deleteObjects:[NCChatMessage objectsWithPredicate:query]];
- [realm deleteObjects:[NCChatBlock objectsWithPredicate:query]];
- [realm deleteObjects:[NCContact objectsWithPredicate:query]];
- [realm deleteObjects:[FederatedCapabilities objectsWithPredicate:query]];
- if (isLastAccount) {
- [realm deleteObjects:[ABContact allObjects]];
- }
- [realm commitWriteTransaction];
- }
- - (void)increaseUnreadBadgeNumberForAccountId:(NSString *)accountId
- {
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm beginWriteTransaction];
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@", accountId];
- TalkAccount *account = [TalkAccount objectsWithPredicate:query].firstObject;
- account.unreadBadgeNumber += 1;
- account.unreadNotification = YES;
- [realm commitWriteTransaction];
- }
- - (void)decreaseUnreadBadgeNumberForAccountId:(NSString *)accountId
- {
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm beginWriteTransaction];
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@", accountId];
- TalkAccount *account = [TalkAccount objectsWithPredicate:query].firstObject;
- account.unreadBadgeNumber = (account.unreadBadgeNumber > 0) ? account.unreadBadgeNumber - 1 : 0;
- account.unreadNotification = (account.unreadBadgeNumber > 0) ? account.unreadNotification : NO;
- [realm commitWriteTransaction];
- }
- - (void)resetUnreadBadgeNumberForAccountId:(NSString *)accountId
- {
- BGTaskHelper *bgTask = [BGTaskHelper startBackgroundTaskWithName:@"resetUnreadBadgeNumberForAccountId" expirationHandler:nil];
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm beginWriteTransaction];
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@", accountId];
- TalkAccount *account = [TalkAccount objectsWithPredicate:query].firstObject;
- account.unreadBadgeNumber = 0;
- account.unreadNotification = NO;
- [realm commitWriteTransaction];
- [bgTask stopBackgroundTask];
- }
- - (NSInteger)numberOfInactiveAccountsWithUnreadNotifications
- {
- return [TalkAccount objectsWhere:(@"active = false AND unreadNotification = true")].count;
- }
- - (NSInteger)numberOfUnreadNotifications
- {
- NSInteger unreadNotifications = 0;
- for (TalkAccount *account in [TalkAccount allObjects]) {
- unreadNotifications += account.unreadBadgeNumber;
- }
- return unreadNotifications;
- }
- - (void)removeUnreadNotificationForInactiveAccounts
- {
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm beginWriteTransaction];
- for (TalkAccount *account in [TalkAccount allObjects]) {
- account.unreadNotification = NO;
- }
- [realm commitWriteTransaction];
- }
- - (void)updateTalkConfigurationHashForAccountId:(NSString *)accountId withHash:(nonnull NSString *)hash
- {
- BGTaskHelper *bgTask = [BGTaskHelper startBackgroundTaskWithName:@"updateTalkConfigurationHashForAccountId" expirationHandler:nil];
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm beginWriteTransaction];
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@", accountId];
- TalkAccount *account = [TalkAccount objectsWithPredicate:query].firstObject;
- account.lastReceivedConfigurationHash = hash;
- [realm commitWriteTransaction];
- [bgTask stopBackgroundTask];
- }
- - (void)updateLastModifiedSinceForAccountId:(NSString *)accountId with:(nonnull NSString *)modifiedSince
- {
- BGTaskHelper *bgTask = [BGTaskHelper startBackgroundTaskWithName:@"updateLastModifiedSinceForAccountId" expirationHandler:nil];
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm beginWriteTransaction];
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@", accountId];
- TalkAccount *account = [TalkAccount objectsWithPredicate:query].firstObject;
- account.lastReceivedModifiedSince = modifiedSince;
- [realm commitWriteTransaction];
- [bgTask stopBackgroundTask];
- }
- #pragma mark - Rooms
- - (NCRoom *)roomWithToken:(NSString *)token forAccountId:(NSString *)accountId
- {
- NCRoom *unmanagedRoom = nil;
- NSPredicate *query = [NSPredicate predicateWithFormat:@"token = %@ AND accountId = %@", token, accountId];
- NCRoom *managedRoom = [NCRoom objectsWithPredicate:query].firstObject;
- if (managedRoom) {
- unmanagedRoom = [[NCRoom alloc] initWithValue:managedRoom];
- }
- return unmanagedRoom;
- }
- #pragma mark - Talk capabilities
- - (void)setTalkCapabilities:(NSDictionary *)capabilitiesDict onTalkCapabilitiesObject:(TalkCapabilities *)capabilities
- {
- capabilities.talkCapabilities = [capabilitiesDict objectForKey:@"features"];
- capabilities.hasTranslationProviders = [[[[capabilitiesDict objectForKey:@"config"] objectForKey:@"chat"] objectForKey:@"has-translation-providers"] boolValue];
- capabilities.attachmentsAllowed = [[[[capabilitiesDict objectForKey:@"config"] objectForKey:@"attachments"] objectForKey:@"allowed"] boolValue];
- capabilities.attachmentsFolder = [[[capabilitiesDict objectForKey:@"config"] objectForKey:@"attachments"] objectForKey:@"folder"];
- capabilities.talkVersion = [capabilitiesDict objectForKey:@"version"];
- NSDictionary *talkConfig = [capabilitiesDict objectForKey:@"config"];
- // Call capabilities
- NSDictionary *callConfig = [talkConfig objectForKey:@"call"];
- NSArray *callConfigKeys = [callConfig allKeys];
- if ([callConfigKeys containsObject:@"enabled"]) {
- capabilities.callEnabled = [[callConfig objectForKey:@"enabled"] boolValue];
- } else {
- capabilities.callEnabled = YES;
- }
- if ([callConfigKeys containsObject:@"recording"]) {
- capabilities.recordingEnabled = [[callConfig objectForKey:@"recording"] boolValue];
- } else {
- capabilities.recordingEnabled = NO;
- }
- if ([callConfigKeys containsObject:@"supported-reactions"]) {
- capabilities.callReactions = [callConfig objectForKey:@"supported-reactions"];
- } else {
- capabilities.callReactions = (RLMArray<RLMString> *)@[];
- }
- // Conversation capabilities
- NSDictionary *conversationConfig = [talkConfig objectForKey:@"conversation"];
- NSArray *conversationConfigKeys = [conversationConfig allKeys];
- if ([conversationConfigKeys containsObject:@"can-create"]) {
- capabilities.canCreate = [[conversationConfig objectForKey:@"can-create"] boolValue];
- } else {
- capabilities.canCreate = YES;
- }
- // Chat capabilities
- NSDictionary *chatConfig = [talkConfig objectForKey:@"chat"];
- NSArray *chatConfigKeys = [chatConfig allKeys];
- capabilities.readStatusPrivacy = [[chatConfig objectForKey:@"read-privacy"] boolValue];
- capabilities.chatMaxLength = [[chatConfig objectForKey:@"max-length"] integerValue];
- if ([chatConfigKeys containsObject:@"typing-privacy"]) {
- capabilities.typingPrivacy = [[chatConfig objectForKey:@"typing-privacy"] boolValue];
- } else {
- capabilities.typingPrivacy = YES;
- }
- // Translations
- id translations = [[[capabilitiesDict objectForKey:@"config"] objectForKey:@"chat"] objectForKey:@"translations"];
- if ([translations isKindOfClass:[NSArray class]]) {
- NSError *error;
- NSData *jsonData = [NSJSONSerialization dataWithJSONObject:translations
- options:0
- error:&error];
- if (jsonData) {
- capabilities.translations = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
- } else {
- NSLog(@"Error generating translations JSON string: %@", error);
- }
- }
- // Federation capabilities
- NSDictionary *federationConfig = [talkConfig objectForKey:@"federation"];
- NSArray *federationConfigKeys = [federationConfig allKeys];
- if ([federationConfigKeys containsObject:@"enabled"]) {
- capabilities.federationEnabled = [[federationConfig objectForKey:@"enabled"] boolValue];
- } else {
- capabilities.federationEnabled = NO;
- }
- if ([federationConfigKeys containsObject:@"incoming-enabled"]) {
- capabilities.federationIncomingEnabled = [[federationConfig objectForKey:@"incoming-enabled"] boolValue];
- } else {
- capabilities.federationIncomingEnabled = NO;
- }
- if ([federationConfigKeys containsObject:@"outgoing-enabled"]) {
- capabilities.federationOutgoingEnabled = [[federationConfig objectForKey:@"outgoing-enabled"] boolValue];
- } else {
- capabilities.federationOutgoingEnabled = NO;
- }
- if ([federationConfigKeys containsObject:@"only-trusted-servers"]) {
- capabilities.federationOnlyTrustedServers = [[federationConfig objectForKey:@"only-trusted-servers"] boolValue];
- } else {
- capabilities.federationOnlyTrustedServers = NO;
- }
- NSDictionary *previewConfig = [talkConfig objectForKey:@"previews"];
- NSArray *previewConfigKeys = [previewConfig allKeys];
- if ([previewConfigKeys containsObject:@"max-gif-size"]) {
- capabilities.maxGifSize = [[previewConfig objectForKey:@"max-gif-size"] intValue];
- }
- }
- #pragma mark - Federated capabilities
- - (FederatedCapabilities * __nullable)federatedCapabilitiesForAccountId:(NSString *)accountId remoteServer:(NSString *)remoteServer roomToken:(NSString *)roomToken
- {
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@ AND remoteServer = %@ AND roomToken = %@", accountId, remoteServer, roomToken];
- FederatedCapabilities *managedFederatedCapabilities = [FederatedCapabilities objectsWithPredicate:query].firstObject;
- if (managedFederatedCapabilities) {
- FederatedCapabilities *unmanagedFederatedCapabilities = [[FederatedCapabilities alloc] initWithValue:managedFederatedCapabilities];
- return unmanagedFederatedCapabilities;
- }
- return nil;
- }
- - (void)setFederatedCapabilities:(NSDictionary *)federatedCapabilitiesDict forAccountId:(NSString *)accountId remoteServer:(NSString *)remoteServer roomToken:(NSString *)roomToken withProxyHash:(NSString *)proxyHash
- {
- FederatedCapabilities *federatedCapabilities = [[FederatedCapabilities alloc] init];
- federatedCapabilities.internalId = [NSString stringWithFormat:@"%@@%@@%@", accountId, remoteServer, roomToken];
- federatedCapabilities.accountId = accountId;
- federatedCapabilities.remoteServer = remoteServer;
- federatedCapabilities.roomToken = roomToken;
- [self setTalkCapabilities:federatedCapabilitiesDict onTalkCapabilitiesObject:federatedCapabilities];
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm transactionWithBlock:^{
- [realm addOrUpdateObject:federatedCapabilities];
- // Update the hash
- NSPredicate *query = [NSPredicate predicateWithFormat:@"token = %@ AND accountId = %@", roomToken, accountId];
- NCRoom *managedRoom = [NCRoom objectsWithPredicate:query].firstObject;
- if (managedRoom) {
- managedRoom.lastReceivedProxyHash = proxyHash;
- }
- NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
- [userInfo setObject:accountId forKey:@"accountId"];
- [userInfo setObject:roomToken forKey:@"roomToken"];
- [[NSNotificationCenter defaultCenter] postNotificationName:NCDatabaseManagerRoomCapabilitiesChangedNotification
- object:self
- userInfo:userInfo];
- }];
- }
- #pragma mark - Room capabilities
- - (BOOL)roomHasTalkCapability:(NSString *)capability forRoom:(NCRoom *)room
- {
- if (!room.isFederated) {
- return [self serverHasTalkCapability:capability forAccountId:room.accountId];
- }
- FederatedCapabilities *federatedCapabilities = [self federatedCapabilitiesForAccountId:room.accountId remoteServer:room.remoteServer roomToken:room.token];
- if (!federatedCapabilities) {
- return NO;
- }
- NSArray *talkFeatures = [federatedCapabilities.talkCapabilities valueForKey:@"self"];
- return [talkFeatures containsObject:capability];
- }
- - (TalkCapabilities * __nullable)roomTalkCapabilitiesForRoom:(NCRoom *)room
- {
- if (room.isFederated) {
- FederatedCapabilities *federatedCapabilities = [self federatedCapabilitiesForAccountId:room.accountId remoteServer:room.remoteServer roomToken:room.token];
- if (federatedCapabilities) {
- TalkCapabilities *unmanagedTalkCapabilities = [[TalkCapabilities alloc] initWithValue:federatedCapabilities];
- return unmanagedTalkCapabilities;
- }
- return nil;
- }
- ServerCapabilities *serverCapabilities = [self serverCapabilitiesForAccountId:room.accountId];
- if (serverCapabilities) {
- TalkCapabilities *unmanagedTalkCapabilities = [[TalkCapabilities alloc] initWithValue:serverCapabilities];
- return unmanagedTalkCapabilities;
- }
- return nil;
- }
- #pragma mark - Server capabilities
- - (ServerCapabilities *)serverCapabilities {
- TalkAccount *activeAccount = [self activeAccount];
- return [self serverCapabilitiesForAccountId:activeAccount.accountId];
- }
- - (ServerCapabilities *)serverCapabilitiesForAccountId:(NSString *)accountId
- {
- ServerCapabilities *cachedCapabilities = [self.capabilitiesCache objectForKey:accountId];
- if (cachedCapabilities) {
- return cachedCapabilities;
- }
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@", accountId];
- ServerCapabilities *managedServerCapabilities = [ServerCapabilities objectsWithPredicate:query].firstObject;
- if (managedServerCapabilities) {
- ServerCapabilities *unmanagedServerCapabilities = [[ServerCapabilities alloc] initWithValue:managedServerCapabilities];
- [self.capabilitiesCache setObject:unmanagedServerCapabilities forKey:accountId];
- return unmanagedServerCapabilities;
- }
- return nil;
- }
- - (void)setServerCapabilities:(NSDictionary *)serverCapabilities forAccountId:(NSString *)accountId
- {
- NSDictionary *serverCaps = [serverCapabilities objectForKey:@"capabilities"];
- NSDictionary *coreCaps = [serverCaps objectForKey:@"core"];
- NSDictionary *version = [serverCapabilities objectForKey:@"version"];
- NSDictionary *themingCaps = [serverCaps objectForKey:@"theming"];
- NSDictionary *talkCaps = [serverCaps objectForKey:@"spreed"];
- NSDictionary *userStatusCaps = [serverCaps objectForKey:@"user_status"];
- NSDictionary *provisioningAPICaps = [serverCaps objectForKey:@"provisioning_api"];
- NSDictionary *guestsCaps = [serverCaps objectForKey:@"guests"];
- NSDictionary *notificationsCaps = [serverCaps objectForKey:@"notifications"];
- ServerCapabilities *capabilities = [[ServerCapabilities alloc] init];
- capabilities.accountId = accountId;
- capabilities.name = [themingCaps objectForKey:@"name"];
- capabilities.slogan = [themingCaps objectForKey:@"slogan"];
- capabilities.url = [themingCaps objectForKey:@"url"];
- capabilities.logo = [themingCaps objectForKey:@"logo"];
- capabilities.color = [themingCaps objectForKey:@"color"];
- capabilities.colorElement = [themingCaps objectForKey:@"color-element"];
- capabilities.colorElementBright = [themingCaps objectForKey:@"color-element-bright"];
- capabilities.colorElementDark = [themingCaps objectForKey:@"color-element-dark"];
- capabilities.colorText = [themingCaps objectForKey:@"color-text"];
- capabilities.background = [themingCaps objectForKey:@"background"];
- capabilities.backgroundDefault = [[themingCaps objectForKey:@"background-default"] boolValue];
- capabilities.backgroundPlain = [[themingCaps objectForKey:@"background-plain"] boolValue];
- capabilities.version = [version objectForKey:@"string"];
- capabilities.versionMajor = [[version objectForKey:@"major"] integerValue];
- capabilities.versionMinor = [[version objectForKey:@"minor"] integerValue];
- capabilities.versionMicro = [[version objectForKey:@"micro"] integerValue];
- capabilities.edition = [version objectForKey:@"edition"];
- capabilities.userStatus = [[userStatusCaps objectForKey:@"enabled"] boolValue];
- capabilities.extendedSupport = [[version objectForKey:@"extendedSupport"] boolValue];
- capabilities.accountPropertyScopesVersion2 = [[provisioningAPICaps objectForKey:@"AccountPropertyScopesVersion"] integerValue] == 2;
- capabilities.accountPropertyScopesFederationEnabled = [[provisioningAPICaps objectForKey:@"AccountPropertyScopesFederationEnabled"] boolValue];
- capabilities.accountPropertyScopesFederatedEnabled = [[provisioningAPICaps objectForKey:@"AccountPropertyScopesFederatedEnabled"] boolValue];
- capabilities.accountPropertyScopesPublishedEnabled = [[provisioningAPICaps objectForKey:@"AccountPropertyScopesPublishedEnabled"] boolValue];
- capabilities.guestsAppEnabled = [[guestsCaps objectForKey:@"enabled"] boolValue];
- capabilities.referenceApiSupported = [[coreCaps objectForKey:@"reference-api"] boolValue];
- capabilities.modRewriteWorking = [[coreCaps objectForKey:@"mod-rewrite-working"] boolValue];
- capabilities.notificationsCapabilities = [notificationsCaps objectForKey:@"ocs-endpoints"];
- [self setTalkCapabilities:talkCaps onTalkCapabilitiesObject:capabilities];
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm transactionWithBlock:^{
- [realm addOrUpdateObject:capabilities];
- }];
- ServerCapabilities *unmanagedServerCapabilities = [[ServerCapabilities alloc] initWithValue:capabilities];
- [self.capabilitiesCache setObject:unmanagedServerCapabilities forKey:accountId];
- }
- - (BOOL)serverHasTalkCapability:(NSString *)capability
- {
- TalkAccount *activeAccount = [self activeAccount];
- return [self serverHasTalkCapability:capability forAccountId:activeAccount.accountId];
- }
- - (BOOL)serverHasTalkCapability:(NSString *)capability forAccountId:(NSString *)accountId
- {
- ServerCapabilities *serverCapabilities = [self serverCapabilitiesForAccountId:accountId];
- if (serverCapabilities) {
- NSArray *talkFeatures = [serverCapabilities.talkCapabilities valueForKey:@"self"];
- if ([talkFeatures containsObject:capability]) {
- return YES;
- }
- }
- return NO;
- }
- - (BOOL)serverHasNotificationsCapability:(NSString *)capability forAccountId:(NSString *)accountId
- {
- ServerCapabilities *serverCapabilities = [self serverCapabilitiesForAccountId:accountId];
- if (serverCapabilities) {
- NSArray *notificationsFeatures = [serverCapabilities.notificationsCapabilities valueForKey:@"self"];
- if ([notificationsFeatures containsObject:capability]) {
- return YES;
- }
- }
- return NO;
- }
- - (BOOL)serverCanInviteFederatedUsersforAccountId:(NSString *)accountId
- {
- ServerCapabilities *serverCapabilities = [self serverCapabilitiesForAccountId:accountId];
- if (serverCapabilities && [self serverHasTalkCapability:kCapabilityFederationV1 forAccountId:accountId]) {
- return serverCapabilities.federationEnabled && serverCapabilities.federationOutgoingEnabled;
- }
- return NO;
- }
- - (void)setExternalSignalingServerVersion:(NSString *)version forAccountId:(NSString *)accountId
- {
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm transactionWithBlock:^{
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@", accountId];
- ServerCapabilities *managedServerCapabilities = [ServerCapabilities objectsWithPredicate:query].firstObject;
- if (managedServerCapabilities && managedServerCapabilities.externalSignalingServerVersion != version) {
- managedServerCapabilities.externalSignalingServerVersion = version;
- ServerCapabilities *unmanagedServerCapabilities = [[ServerCapabilities alloc] initWithValue:managedServerCapabilities];
- [self.capabilitiesCache setObject:unmanagedServerCapabilities forKey:accountId];
- }
- }];
- }
- - (BOOL)hasAvailableTranslationsForAccountId:(NSString *)accountId
- {
- return [self hasTranslationProvidersForAccountId:accountId] || [self availableTranslationsForAccountId:accountId].count > 0;
- }
- - (BOOL)hasTranslationProvidersForAccountId:(NSString *)accountId
- {
- ServerCapabilities *serverCapabilities = [self serverCapabilitiesForAccountId:accountId];
- return serverCapabilities.hasTranslationProviders;
- }
- - (NSArray *)availableTranslationsForAccountId:(NSString *)accountId
- {
- ServerCapabilities *serverCapabilities = [self serverCapabilitiesForAccountId:accountId];
- if (serverCapabilities) {
- NSArray *translations = [self translationsArrayFromTranslationsJSONString:serverCapabilities.translations];
- return [self translationsFromTranslationsArray:translations];
- }
- return @[];
- }
- - (NSArray *)translationsArrayFromTranslationsJSONString:(NSString *)translations
- {
- NSArray *translationsArray = @[];
- NSData *data = [translations dataUsingEncoding:NSUTF8StringEncoding];
- if (data) {
- NSError* error;
- NSArray* jsonData = [NSJSONSerialization JSONObjectWithData:data
- options:0
- error:&error];
- if (jsonData) {
- translationsArray = jsonData;
- } else {
- NSLog(@"Error retrieving translations JSON data: %@", error);
- }
- }
- return translationsArray;
- }
- - (NSArray *)translationsFromTranslationsArray:(NSArray *)translations
- {
- NSMutableArray *availableTranslations = [NSMutableArray new];
- for (NSDictionary *translationDict in translations) {
- NCTranslation *translation = [[NCTranslation alloc] init];
- translation.from = [translationDict objectForKey:@"from"];
- translation.fromLabel = [translationDict objectForKey:@"fromLabel"];
- translation.to = [translationDict objectForKey:@"to"];
- translation.toLabel = [translationDict objectForKey:@"toLabel"];
- [availableTranslations addObject:translation];
- }
- return availableTranslations;
- }
- - (void)increasePendingFederationInvitationForAccountId:(NSString *)accountId
- {
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm beginWriteTransaction];
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@", accountId];
- TalkAccount *account = [TalkAccount objectsWithPredicate:query].firstObject;
- account.pendingFederationInvitations += 1;
- [realm commitWriteTransaction];
- }
- - (void)decreasePendingFederationInvitationForAccountId:(NSString *)accountId
- {
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm beginWriteTransaction];
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@", accountId];
- TalkAccount *account = [TalkAccount objectsWithPredicate:query].firstObject;
- account.pendingFederationInvitations = (account.pendingFederationInvitations > 0) ? account.pendingFederationInvitations - 1 : 0;
- [realm commitWriteTransaction];
- [[NSNotificationCenter defaultCenter] postNotificationName:NCDatabaseManagerPendingFederationInvitationsDidChange
- object:self
- userInfo:nil];
- }
- - (void)setPendingFederationInvitationForAccountId:(NSString *)accountId with:(NSInteger)numberOfPendingInvitations
- {
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm beginWriteTransaction];
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@", accountId];
- TalkAccount *account = [TalkAccount objectsWithPredicate:query].firstObject;
- account.pendingFederationInvitations = numberOfPendingInvitations;
- [realm commitWriteTransaction];
- [[NSNotificationCenter defaultCenter] postNotificationName:NCDatabaseManagerPendingFederationInvitationsDidChange
- object:self
- userInfo:nil];
- }
- - (void)updateLastFederationInvitationUpdateForAccountId:(NSString *)accountId withTimestamp:(NSInteger)timestamp
- {
- BGTaskHelper *bgTask = [BGTaskHelper startBackgroundTaskWithName:@"updateLastFederationInvitationUpdateForAccountId" expirationHandler:nil];
- RLMRealm *realm = [RLMRealm defaultRealm];
- [realm beginWriteTransaction];
- NSPredicate *query = [NSPredicate predicateWithFormat:@"accountId = %@", accountId];
- TalkAccount *account = [TalkAccount objectsWithPredicate:query].firstObject;
- account.lastPendingFederationInvitationFetch = timestamp;
- [realm commitWriteTransaction];
- [bgTask stopBackgroundTask];
- }
- @end
|